diff --git a/pkg/dwarf/dwarfbuilder/info.go b/pkg/dwarf/dwarfbuilder/info.go index 95b0f05d..7cc5b94f 100644 --- a/pkg/dwarf/dwarfbuilder/info.go +++ b/pkg/dwarf/dwarfbuilder/info.go @@ -6,7 +6,7 @@ import ( "encoding/binary" "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, @@ -229,19 +229,19 @@ func (b *Builder) makeAbbrevTable() []byte { var abbrev bytes.Buffer for i := range b.abbrevs { - util.EncodeULEB128(&abbrev, uint64(i+1)) - util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].tag)) + leb128.EncodeUnsigned(&abbrev, uint64(i+1)) + leb128.EncodeUnsigned(&abbrev, uint64(b.abbrevs[i].tag)) if b.abbrevs[i].children { abbrev.WriteByte(0x01) } else { abbrev.WriteByte(0x00) } for j := range b.abbrevs[i].attr { - util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].attr[j])) - util.EncodeULEB128(&abbrev, uint64(b.abbrevs[i].form[j])) + leb128.EncodeUnsigned(&abbrev, uint64(b.abbrevs[i].attr[j])) + leb128.EncodeUnsigned(&abbrev, uint64(b.abbrevs[i].form[j])) } - util.EncodeULEB128(&abbrev, 0) - util.EncodeULEB128(&abbrev, 0) + leb128.EncodeUnsigned(&abbrev, 0) + leb128.EncodeUnsigned(&abbrev, 0) } return abbrev.Bytes() diff --git a/pkg/dwarf/dwarfbuilder/loc.go b/pkg/dwarf/dwarfbuilder/loc.go index 357be789..f89e6e7c 100644 --- a/pkg/dwarf/dwarfbuilder/loc.go +++ b/pkg/dwarf/dwarfbuilder/loc.go @@ -3,8 +3,8 @@ package dwarfbuilder import ( "bytes" + "github.com/go-delve/delve/pkg/dwarf/leb128" "github.com/go-delve/delve/pkg/dwarf/op" - "github.com/go-delve/delve/pkg/dwarf/util" ) // LocEntry represents one entry of debug_loc. @@ -23,9 +23,9 @@ func LocationBlock(args ...interface{}) []byte { case op.Opcode: buf.WriteByte(byte(x)) case int: - util.EncodeSLEB128(&buf, int64(x)) + leb128.EncodeSigned(&buf, int64(x)) case uint: - util.EncodeULEB128(&buf, uint64(x)) + leb128.EncodeUnsigned(&buf, uint64(x)) default: panic("unsupported value type") } diff --git a/pkg/dwarf/frame/parser.go b/pkg/dwarf/frame/parser.go index 147ca34f..e9c638ec 100644 --- a/pkg/dwarf/frame/parser.go +++ b/pkg/dwarf/frame/parser.go @@ -9,6 +9,7 @@ import ( "fmt" "io" + "github.com/go-delve/delve/pkg/dwarf/leb128" "github.com/go-delve/delve/pkg/dwarf/util" ) @@ -123,10 +124,10 @@ func parseFDE(ctx *parseContext) parsefunc { ctx.entries = append(ctx.entries, ctx.frame) 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 // size followed by 'size' bytes. - n, _ := util.DecodeULEB128(reader) + n, _ := leb128.DecodeUnsigned(reader) reader.Seek(int64(n), io.SeekCurrent) } @@ -165,23 +166,23 @@ func parseCIE(ctx *parseContext) parsefunc { } // parse code alignment factor - ctx.common.CodeAlignmentFactor, _ = util.DecodeULEB128(buf) + ctx.common.CodeAlignmentFactor, _ = leb128.DecodeUnsigned(buf) // parse data alignment factor - ctx.common.DataAlignmentFactor, _ = util.DecodeSLEB128(buf) + ctx.common.DataAlignmentFactor, _ = leb128.DecodeSigned(buf) // parse return address register if ctx.parsingEHFrame() && ctx.common.Version == 1 { b, _ := buf.ReadByte() ctx.common.ReturnAddressRegister = uint64(b) } else { - ctx.common.ReturnAddressRegister, _ = util.DecodeULEB128(buf) + ctx.common.ReturnAddressRegister, _ = leb128.DecodeUnsigned(buf) } ctx.common.ptrEncAddr = ptrEncAbs 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++ { switch ctx.common.Augmentation[i] { 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 // mapped to when the executable file containing the eh_frame section being // 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 { return 0 } @@ -242,7 +243,7 @@ func (ctx *parseContext) readEncodedPtr(addr uint64, buf util.ByteReaderWithLen, case ptrEncAbs, ptrEncSigned: ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, ctx.ptrSize) case ptrEncUleb: - ptr, _ = util.DecodeULEB128(buf) + ptr, _ = leb128.DecodeUnsigned(buf) case ptrEncUdata2: ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 2) case ptrEncSdata2: @@ -256,7 +257,7 @@ func (ctx *parseContext) readEncodedPtr(addr uint64, buf util.ByteReaderWithLen, case ptrEncUdata8, ptrEncSdata8: ptr, _ = util.ReadUintRaw(buf, binary.LittleEndian, 8) case ptrEncSleb: - n, _ := util.DecodeSLEB128(buf) + n, _ := leb128.DecodeSigned(buf) ptr = uint64(n) } diff --git a/pkg/dwarf/frame/table.go b/pkg/dwarf/frame/table.go index a0f3f1e3..c49d2115 100644 --- a/pkg/dwarf/frame/table.go +++ b/pkg/dwarf/frame/table.go @@ -5,7 +5,7 @@ import ( "encoding/binary" "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. @@ -254,7 +254,7 @@ func offset(frame *FrameContext) { var ( 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} @@ -284,26 +284,26 @@ func setloc(frame *FrameContext) { func offsetextended(frame *FrameContext) { var ( - reg, _ = util.DecodeULEB128(frame.buf) - offset, _ = util.DecodeULEB128(frame.buf) + reg, _ = leb128.DecodeUnsigned(frame.buf) + offset, _ = leb128.DecodeUnsigned(frame.buf) ) frame.Regs[reg] = DWRule{Offset: int64(offset) * frame.dataAlignment, Rule: RuleOffset} } func undefined(frame *FrameContext) { - reg, _ := util.DecodeULEB128(frame.buf) + reg, _ := leb128.DecodeUnsigned(frame.buf) frame.Regs[reg] = DWRule{Rule: RuleUndefined} } func samevalue(frame *FrameContext) { - reg, _ := util.DecodeULEB128(frame.buf) + reg, _ := leb128.DecodeUnsigned(frame.buf) frame.Regs[reg] = DWRule{Rule: RuleSameVal} } func register(frame *FrameContext) { - reg1, _ := util.DecodeULEB128(frame.buf) - reg2, _ := util.DecodeULEB128(frame.buf) + reg1, _ := leb128.DecodeUnsigned(frame.buf) + reg2, _ := leb128.DecodeUnsigned(frame.buf) frame.Regs[reg1] = DWRule{Reg: reg2, Rule: RuleRegister} } @@ -316,7 +316,7 @@ func restorestate(frame *FrameContext) { } func restoreextended(frame *FrameContext) { - reg, _ := util.DecodeULEB128(frame.buf) + reg, _ := leb128.DecodeUnsigned(frame.buf) oldrule, ok := frame.initialRegs[reg] if ok { @@ -327,8 +327,8 @@ func restoreextended(frame *FrameContext) { } func defcfa(frame *FrameContext) { - reg, _ := util.DecodeULEB128(frame.buf) - offset, _ := util.DecodeULEB128(frame.buf) + reg, _ := leb128.DecodeUnsigned(frame.buf) + offset, _ := leb128.DecodeUnsigned(frame.buf) frame.CFA.Rule = RuleCFA frame.CFA.Reg = reg @@ -336,18 +336,18 @@ func defcfa(frame *FrameContext) { } func defcfaregister(frame *FrameContext) { - reg, _ := util.DecodeULEB128(frame.buf) + reg, _ := leb128.DecodeUnsigned(frame.buf) frame.CFA.Reg = reg } func defcfaoffset(frame *FrameContext) { - offset, _ := util.DecodeULEB128(frame.buf) + offset, _ := leb128.DecodeUnsigned(frame.buf) frame.CFA.Offset = int64(offset) } func defcfasf(frame *FrameContext) { - reg, _ := util.DecodeULEB128(frame.buf) - offset, _ := util.DecodeSLEB128(frame.buf) + reg, _ := leb128.DecodeUnsigned(frame.buf) + offset, _ := leb128.DecodeSigned(frame.buf) frame.CFA.Rule = RuleCFA frame.CFA.Reg = reg @@ -355,14 +355,14 @@ func defcfasf(frame *FrameContext) { } func defcfaoffsetsf(frame *FrameContext) { - offset, _ := util.DecodeSLEB128(frame.buf) + offset, _ := leb128.DecodeSigned(frame.buf) offset *= frame.dataAlignment frame.CFA.Offset = offset } func defcfaexpression(frame *FrameContext) { var ( - l, _ = util.DecodeULEB128(frame.buf) + l, _ = leb128.DecodeUnsigned(frame.buf) expr = frame.buf.Next(int(l)) ) @@ -372,8 +372,8 @@ func defcfaexpression(frame *FrameContext) { func expression(frame *FrameContext) { var ( - reg, _ = util.DecodeULEB128(frame.buf) - l, _ = util.DecodeULEB128(frame.buf) + reg, _ = leb128.DecodeUnsigned(frame.buf) + l, _ = leb128.DecodeUnsigned(frame.buf) expr = frame.buf.Next(int(l)) ) @@ -382,8 +382,8 @@ func expression(frame *FrameContext) { func offsetextendedsf(frame *FrameContext) { var ( - reg, _ = util.DecodeULEB128(frame.buf) - offset, _ = util.DecodeSLEB128(frame.buf) + reg, _ = leb128.DecodeUnsigned(frame.buf) + offset, _ = leb128.DecodeSigned(frame.buf) ) frame.Regs[reg] = DWRule{Offset: offset * frame.dataAlignment, Rule: RuleOffset} @@ -391,8 +391,8 @@ func offsetextendedsf(frame *FrameContext) { func valoffset(frame *FrameContext) { var ( - reg, _ = util.DecodeULEB128(frame.buf) - offset, _ = util.DecodeULEB128(frame.buf) + reg, _ = leb128.DecodeUnsigned(frame.buf) + offset, _ = leb128.DecodeUnsigned(frame.buf) ) frame.Regs[reg] = DWRule{Offset: int64(offset), Rule: RuleValOffset} @@ -400,8 +400,8 @@ func valoffset(frame *FrameContext) { func valoffsetsf(frame *FrameContext) { var ( - reg, _ = util.DecodeULEB128(frame.buf) - offset, _ = util.DecodeSLEB128(frame.buf) + reg, _ = leb128.DecodeUnsigned(frame.buf) + offset, _ = leb128.DecodeSigned(frame.buf) ) frame.Regs[reg] = DWRule{Offset: offset * frame.dataAlignment, Rule: RuleValOffset} @@ -409,8 +409,8 @@ func valoffsetsf(frame *FrameContext) { func valexpression(frame *FrameContext) { var ( - reg, _ = util.DecodeULEB128(frame.buf) - l, _ = util.DecodeULEB128(frame.buf) + reg, _ = leb128.DecodeUnsigned(frame.buf) + l, _ = leb128.DecodeUnsigned(frame.buf) expr = frame.buf.Next(int(l)) ) diff --git a/pkg/dwarf/leb128/decode.go b/pkg/dwarf/leb128/decode.go new file mode 100644 index 00000000..61f0aa3c --- /dev/null +++ b/pkg/dwarf/leb128/decode.go @@ -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 +} diff --git a/pkg/dwarf/leb128/decode_test.go b/pkg/dwarf/leb128/decode_test.go new file mode 100644 index 00000000..f9049bc7 --- /dev/null +++ b/pkg/dwarf/leb128/decode_test.go @@ -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) + } +} diff --git a/pkg/dwarf/leb128/doc.go b/pkg/dwarf/leb128/doc.go new file mode 100644 index 00000000..73f5a0f6 --- /dev/null +++ b/pkg/dwarf/leb128/doc.go @@ -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 diff --git a/pkg/dwarf/leb128/encode.go b/pkg/dwarf/leb128/encode.go new file mode 100644 index 00000000..c4f1a232 --- /dev/null +++ b/pkg/dwarf/leb128/encode.go @@ -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 + } + } +} diff --git a/pkg/dwarf/leb128/encode_test.go b/pkg/dwarf/leb128/encode_test.go new file mode 100644 index 00000000..f344b7c8 --- /dev/null +++ b/pkg/dwarf/leb128/encode_test.go @@ -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") + } + } +} diff --git a/pkg/dwarf/line/line_parser.go b/pkg/dwarf/line/line_parser.go index 19d2ae20..a6bb4995 100644 --- a/pkg/dwarf/line/line_parser.go +++ b/pkg/dwarf/line/line_parser.go @@ -6,6 +6,7 @@ import ( "path" "strings" + "github.com/go-delve/delve/pkg/dwarf/leb128" "github.com/go-delve/delve/pkg/dwarf/util" ) @@ -173,7 +174,7 @@ func parseIncludeDirs5(info *DebugLineInfo, buf *bytes.Buffer) bool { if dirEntryFormReader == nil { return false } - dirCount, _ := util.DecodeULEB128(buf) + dirCount, _ := leb128.DecodeUnsigned(buf) info.IncludeDirs = make([]string, 0, dirCount) for i := uint64(0); i < dirCount; i++ { dirEntryFormReader.reset() @@ -242,9 +243,9 @@ func readFileEntry(info *DebugLineInfo, buf *bytes.Buffer, exitOnEmptyPath bool) entry.Path = strings.ReplaceAll(entry.Path, "\\", "/") } - entry.DirIdx, _ = util.DecodeULEB128(buf) - entry.LastModTime, _ = util.DecodeULEB128(buf) - entry.Length, _ = util.DecodeULEB128(buf) + entry.DirIdx, _ = leb128.DecodeUnsigned(buf) + entry.LastModTime, _ = leb128.DecodeUnsigned(buf) + entry.Length, _ = leb128.DecodeUnsigned(buf) if !pathIsAbs(entry.Path) { if entry.DirIdx < uint64(len(info.IncludeDirs)) { 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 { return false } - fileCount, _ := util.DecodeULEB128(buf) + fileCount, _ := leb128.DecodeUnsigned(buf) info.FileNames = make([]*FileEntry, 0, fileCount) for i := 0; i < int(fileCount); i++ { var ( diff --git a/pkg/dwarf/line/parse_util.go b/pkg/dwarf/line/parse_util.go index 867d9b7b..4f2e5bbf 100644 --- a/pkg/dwarf/line/parse_util.go +++ b/pkg/dwarf/line/parse_util.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "errors" + "github.com/go-delve/delve/pkg/dwarf/leb128" "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), } for i := range r.contentTypes { - r.contentTypes[i], _ = util.DecodeULEB128(buf) - r.formCodes[i], _ = util.DecodeULEB128(buf) + r.contentTypes[i], _ = leb128.DecodeUnsigned(buf) + r.formCodes[i], _ = leb128.DecodeUnsigned(buf) } return r } @@ -94,7 +95,7 @@ func (rdr *formReader) next(buf *bytes.Buffer) bool { switch rdr.formCode { case _DW_FORM_block: - n, _ := util.DecodeULEB128(buf) + n, _ := leb128.DecodeUnsigned(buf) rdr.readBlock(buf, n) case _DW_FORM_block1: @@ -150,10 +151,10 @@ func (rdr *formReader) next(buf *bytes.Buffer) bool { rdr.readBlock(buf, 16) case _DW_FORM_sdata: - rdr.i64, _ = util.DecodeSLEB128(buf) + rdr.i64, _ = leb128.DecodeSigned(buf) case _DW_FORM_udata, _DW_FORM_strx: - rdr.u64, _ = util.DecodeULEB128(buf) + rdr.u64, _ = leb128.DecodeUnsigned(buf) case _DW_FORM_string: rdr.str, _ = util.ParseString(buf) diff --git a/pkg/dwarf/line/state_machine.go b/pkg/dwarf/line/state_machine.go index 691b57a9..79227953 100644 --- a/pkg/dwarf/line/state_machine.go +++ b/pkg/dwarf/line/state_machine.go @@ -7,6 +7,7 @@ import ( "fmt" "io" + "github.com/go-delve/delve/pkg/dwarf/leb128" "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 opnum := sm.dbl.Prologue.StdOpLengths[b-1] 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) } @@ -432,7 +433,7 @@ func execSpecialOpcode(sm *StateMachine, instr byte) { } func execExtendedOpcode(sm *StateMachine, buf *bytes.Buffer) { - _, _ = util.DecodeULEB128(buf) + _, _ = leb128.DecodeUnsigned(buf) b, _ := buf.ReadByte() if fn, ok := extendedopcodes[b]; ok { fn(sm, buf) @@ -444,18 +445,18 @@ func copyfn(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) } func advanceline(sm *StateMachine, buf *bytes.Buffer) { - line, _ := util.DecodeSLEB128(buf) + line, _ := leb128.DecodeSigned(buf) sm.line += int(line) sm.lastDelta = int(line) } func setfile(sm *StateMachine, buf *bytes.Buffer) { - i, _ := util.DecodeULEB128(buf) + i, _ := leb128.DecodeUnsigned(buf) if sm.dbl.Prologue.Version < 5 { // in DWARF v5 files are indexed starting from 0, in v4 and prior the index starts at 1 i-- @@ -473,7 +474,7 @@ func setfile(sm *StateMachine, buf *bytes.Buffer) { } func setcolumn(sm *StateMachine, buf *bytes.Buffer) { - c, _ := util.DecodeULEB128(buf) + c, _ := leb128.DecodeUnsigned(buf) sm.column = uint(c) } @@ -510,7 +511,7 @@ func setaddress(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) { @@ -528,6 +529,6 @@ func epiloguebegin(sm *StateMachine, buf *bytes.Buffer) { } func setisa(sm *StateMachine, buf *bytes.Buffer) { - c, _ := util.DecodeULEB128(buf) + c, _ := leb128.DecodeUnsigned(buf) sm.isa = c } diff --git a/pkg/dwarf/line/state_machine_test.go b/pkg/dwarf/line/state_machine_test.go index b7281151..3eb47ef3 100644 --- a/pkg/dwarf/line/state_machine_test.go +++ b/pkg/dwarf/line/state_machine_test.go @@ -13,6 +13,7 @@ import ( "runtime" "testing" + "github.com/go-delve/delve/pkg/dwarf/leb128" "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) { instr.WriteByte(0) - util.EncodeULEB128(instr, 9) // 1 + ptr_size + leb128.EncodeUnsigned(instr, 9) // 1 + ptr_size instr.WriteByte(DW_LINE_set_address) util.WriteUint(instr, binary.LittleEndian, ptrSize, addr) } @@ -147,17 +148,17 @@ func TestMultipleSequences(t *testing.T) { write_DW_LNS_advance_pc := func(off uint64) { instr.WriteByte(DW_LNS_advance_pc) - util.EncodeULEB128(instr, off) + leb128.EncodeUnsigned(instr, off) } write_DW_LNS_advance_line := func(off int64) { instr.WriteByte(DW_LNS_advance_line) - util.EncodeSLEB128(instr, off) + leb128.EncodeSigned(instr, off) } write_DW_LNE_end_sequence := func() { instr.WriteByte(0) - util.EncodeULEB128(instr, 1) + leb128.EncodeUnsigned(instr, 1) instr.WriteByte(DW_LINE_end_sequence) } diff --git a/pkg/dwarf/loclist/dwarf5_loclist.go b/pkg/dwarf/loclist/dwarf5_loclist.go index b0e371d1..110bd8c8 100644 --- a/pkg/dwarf/loclist/dwarf5_loclist.go +++ b/pkg/dwarf/loclist/dwarf5_loclist.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/go-delve/delve/pkg/dwarf/godwarf" + "github.com/go-delve/delve/pkg/dwarf/leb128" "github.com/go-delve/delve/pkg/dwarf/util" ) @@ -116,7 +117,7 @@ func (it *loclistsIterator) next() bool { return false case _DW_LLE_base_addressx: - baseIdx, _ := util.DecodeULEB128(it.buf) + baseIdx, _ := leb128.DecodeUnsigned(it.buf) if err != nil { it.err = err return false @@ -126,8 +127,8 @@ func (it *loclistsIterator) next() bool { it.onRange = false case _DW_LLE_startx_endx: - startIdx, _ := util.DecodeULEB128(it.buf) - endIdx, _ := util.DecodeULEB128(it.buf) + startIdx, _ := leb128.DecodeUnsigned(it.buf) + endIdx, _ := leb128.DecodeUnsigned(it.buf) it.readInstr() it.start, it.err = it.debugAddr.Get(startIdx) @@ -137,8 +138,8 @@ func (it *loclistsIterator) next() bool { it.onRange = true case _DW_LLE_startx_length: - startIdx, _ := util.DecodeULEB128(it.buf) - length, _ := util.DecodeULEB128(it.buf) + startIdx, _ := leb128.DecodeUnsigned(it.buf) + length, _ := leb128.DecodeUnsigned(it.buf) it.readInstr() it.start, it.err = it.debugAddr.Get(startIdx) @@ -146,8 +147,8 @@ func (it *loclistsIterator) next() bool { it.onRange = true case _DW_LLE_offset_pair: - off1, _ := util.DecodeULEB128(it.buf) - off2, _ := util.DecodeULEB128(it.buf) + off1, _ := leb128.DecodeUnsigned(it.buf) + off2, _ := leb128.DecodeUnsigned(it.buf) it.readInstr() it.start = it.base + off1 @@ -172,7 +173,7 @@ func (it *loclistsIterator) next() bool { case _DW_LLE_start_length: 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.end = it.start + length it.onRange = true @@ -188,6 +189,6 @@ func (it *loclistsIterator) next() bool { } func (it *loclistsIterator) readInstr() { - length, _ := util.DecodeULEB128(it.buf) + length, _ := leb128.DecodeUnsigned(it.buf) it.instr = it.buf.Next(int(length)) } diff --git a/pkg/dwarf/loclist/loclist5_test.go b/pkg/dwarf/loclist/loclist5_test.go index f041d295..5bf692cb 100644 --- a/pkg/dwarf/loclist/loclist5_test.go +++ b/pkg/dwarf/loclist/loclist5_test.go @@ -5,7 +5,7 @@ import ( "encoding/binary" "testing" - "github.com/go-delve/delve/pkg/dwarf/util" + "github.com/go-delve/delve/pkg/dwarf/leb128" ) func TestLoclist5(t *testing.T) { @@ -14,7 +14,7 @@ func TestLoclist5(t *testing.T) { p32 := func(n uint32) { 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) } - 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) p16(0x5) // version diff --git a/pkg/dwarf/op/op.go b/pkg/dwarf/op/op.go index 043942eb..b0889ca9 100644 --- a/pkg/dwarf/op/op.go +++ b/pkg/dwarf/op/op.go @@ -7,6 +7,7 @@ import ( "fmt" "io" + "github.com/go-delve/delve/pkg/dwarf/leb128" "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 switch arg { case 's': - n, _ := util.DecodeSLEB128(in) + n, _ := leb128.DecodeSigned(in) regnum = uint64(n) fmt.Fprintf(out, "%#x ", n) case 'u': - n, _ := util.DecodeULEB128(in) + n, _ := leb128.DecodeUnsigned(in) regnum = n fmt.Fprintf(out, "%#x ", n) case '1': @@ -154,7 +155,7 @@ func PrettyPrint(out io.Writer, instructions []byte, regnumToName func(uint64) s binary.Read(in, binary.LittleEndian, &x) fmt.Fprintf(out, "%#x ", x) case 'B': - sz, _ := util.DecodeULEB128(in) + sz, _ := leb128.DecodeUnsigned(in) data := make([]byte, sz) sz2, _ := in.Read(data) data = data[:sz2] @@ -189,7 +190,7 @@ func (ctxt *context) closeLoc(opcode0 Opcode, piece Piece) error { switch opcode { case DW_OP_piece: - sz, _ := util.DecodeULEB128(ctxt.buf) + sz, _ := leb128.DecodeUnsigned(ctxt.buf) piece.Size = int(sz) ctxt.pieces = append(ctxt.pieces, piece) return nil @@ -222,19 +223,19 @@ func addr(opcode Opcode, ctxt *context) error { func plusuconsts(opcode Opcode, ctxt *context) error { slen := len(ctxt.stack) - num, _ := util.DecodeULEB128(ctxt.buf) + num, _ := leb128.DecodeUnsigned(ctxt.buf) ctxt.stack[slen-1] = ctxt.stack[slen-1] + int64(num) return nil } func consts(opcode Opcode, ctxt *context) error { - num, _ := util.DecodeSLEB128(ctxt.buf) + num, _ := leb128.DecodeSigned(ctxt.buf) ctxt.stack = append(ctxt.stack, num) return nil } 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) return nil } @@ -242,7 +243,7 @@ func framebase(opcode Opcode, ctxt *context) error { func register(opcode Opcode, ctxt *context) error { var regnum uint64 if opcode == DW_OP_regx { - regnum, _ = util.DecodeULEB128(ctxt.buf) + regnum, _ = leb128.DecodeUnsigned(ctxt.buf) } else { regnum = uint64(opcode - DW_OP_reg0) } @@ -252,11 +253,11 @@ func register(opcode Opcode, ctxt *context) error { func bregister(opcode Opcode, ctxt *context) error { var regnum uint64 if opcode == DW_OP_bregx { - regnum, _ = util.DecodeULEB128(ctxt.buf) + regnum, _ = leb128.DecodeUnsigned(ctxt.buf) } else { regnum = uint64(opcode - DW_OP_breg0) } - offset, _ := util.DecodeSLEB128(ctxt.buf) + offset, _ := leb128.DecodeSigned(ctxt.buf) if ctxt.Reg(regnum) == nil { 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 { - sz, _ := util.DecodeULEB128(ctxt.buf) + sz, _ := leb128.DecodeUnsigned(ctxt.buf) if len(ctxt.stack) == 0 { // 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 { - num, _ := util.DecodeULEB128(ctxt.buf) + num, _ := leb128.DecodeUnsigned(ctxt.buf) ctxt.stack = append(ctxt.stack, int64(num)) return nil } @@ -516,7 +517,7 @@ func stackvalue(_ Opcode, ctxt *context) error { } func implicitvalue(_ Opcode, ctxt *context) error { - sz, _ := util.DecodeULEB128(ctxt.buf) + sz, _ := leb128.DecodeUnsigned(ctxt.buf) block := make([]byte, sz) n, _ := ctxt.buf.Read(block) if uint64(n) != sz { diff --git a/pkg/dwarf/util/util.go b/pkg/dwarf/util/util.go index 4e199cb2..c7c98bea 100644 --- a/pkg/dwarf/util/util.go +++ b/pkg/dwarf/util/util.go @@ -6,125 +6,50 @@ import ( "encoding/binary" "fmt" "io" + + "github.com/go-delve/delve/pkg/dwarf/leb128" ) // 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 { io.ByteReader io.Reader 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 // represented number. +// +// Deprecated: use leb128.DecodeUnsigned. func DecodeULEB128(buf ByteReaderWithLen) (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 + return leb128.DecodeUnsigned(buf) } // DecodeSLEB128 decodes a signed Little Endian Base 128 // represented number. +// +// Deprecated: use leb128.DecodeUnsigned. func DecodeSLEB128(buf ByteReaderWithLen) (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 + return leb128.DecodeSigned(buf) } // EncodeULEB128 encodes x to the unsigned Little Endian Base 128 format // into out. +// +// Deprecated: use leb128.EncodeUnsigned. 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 - } - } + leb128.EncodeUnsigned(out, x) } // EncodeSLEB128 encodes x to the signed Little Endian Base 128 format // into out. +// +// Deprecated: use leb128.EncodeSigned. 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 - } - } + leb128.EncodeSigned(out, x) } // ParseString reads a null-terminated string from data. diff --git a/pkg/dwarf/util/util_test.go b/pkg/dwarf/util/util_test.go index 63bb4190..5d21afcc 100644 --- a/pkg/dwarf/util/util_test.go +++ b/pkg/dwarf/util/util_test.go @@ -5,64 +5,6 @@ import ( "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) { bstr := bytes.NewBuffer([]byte{'h', 'i', 0x0, 0xFF, 0xCC}) str, _ := ParseString(bstr)