gocore: add in mpratt's feedback and remove delve dependency This change integrates some feedback from mpratt in CL 635227 that came in after it landed. It also removes the dependency on delve, since this is definitely reaching into internal packages that are not intended to be used by outsiders. Instead, we just copy over what we need. This is safe to copy over because it's largely about immutable formats and functionality: hardware register names and DWARF 2. Change-Id: I5aa8cb9a56b464c0cdb45baf4ea8423989d0afbe Reviewed-on: https://go-review.googlesource.com/c/debug/+/635281 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> Auto-Submit: Michael Knyszek <mknyszek@google.com>
diff --git a/go.mod b/go.mod index 9e03bc5..7db2722 100644 --- a/go.mod +++ b/go.mod
@@ -4,7 +4,6 @@ require ( github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e - github.com/go-delve/delve v1.23.1 github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 golang.org/x/sys v0.28.0
diff --git a/go.sum b/go.sum index 11c30c1..6407e38 100644 --- a/go.sum +++ b/go.sum
@@ -5,8 +5,6 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/go-delve/delve v1.23.1 h1:MtZ13ppptttkqSuvVnwJ5CPhIAzDiOwRrYuCk3ES7fU= -github.com/go-delve/delve v1.23.1/go.mod h1:S3SLuEE2mn7wipKilTvk1p9HdTMnXXElcEpiZ+VcuqU= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
diff --git a/internal/gocore/dwarf.go b/internal/gocore/dwarf.go index 53e711a..019b15a 100644 --- a/internal/gocore/dwarf.go +++ b/internal/gocore/dwarf.go
@@ -13,9 +13,9 @@ "golang.org/x/debug/internal/core" - "github.com/go-delve/delve/pkg/dwarf/loclist" - "github.com/go-delve/delve/pkg/dwarf/op" - "github.com/go-delve/delve/pkg/dwarf/regnum" + "golang.org/x/debug/third_party/delve/dwarf/loclist" + "golang.org/x/debug/third_party/delve/dwarf/op" + "golang.org/x/debug/third_party/delve/dwarf/regnum" ) const ( @@ -272,13 +272,6 @@ return consts, nil } -const ( - _DW_OP_addr = 0x03 - _DW_OP_call_frame_cfa = 0x9c - _DW_OP_plus = 0x22 - _DW_OP_consts = 0x11 -) - func readGlobals(p *core.Process, dwarfTypeMap map[dwarf.Type]*Type) ([]*Root, error) { d, err := p.DWARF() if err != nil { @@ -304,7 +297,7 @@ continue } loc := f.Val.([]byte) - if len(loc) == 0 || loc[0] != _DW_OP_addr { + if len(loc) == 0 || loc[0] != byte(op.DW_OP_addr) { continue } var a core.Address @@ -418,6 +411,11 @@ } name := nf.Val.(string) + // No .debug_loc section, can't make progress. + if len(dLocSec) == 0 { + continue + } + // Read the location list. locListOff := aloc.Val.(int64) dr := loclist.NewDwarf2Reader(dLocSec, int(p.PtrSize()))
diff --git a/internal/gocore/module.go b/internal/gocore/module.go index 3d09d29..f15b9e0 100644 --- a/internal/gocore/module.go +++ b/internal/gocore/module.go
@@ -48,20 +48,9 @@ n := ftab.SliceLen() - 1 // last slot is a dummy, just holds entry for i := int64(0); i < n; i++ { ft := ftab.SliceIndex(i) - var min, max core.Address - var funcoff int64 - if ft.HasField("entryoff") { - min = m.textAddr(ft.Field("entryoff").Uint32()) - max = m.textAddr(ftab.SliceIndex(i + 1).Field("entryoff").Uint32()) - funcoff = int64(ft.Field("funcoff").Uint32()) - } else { - // Prior to 1.18, functab.entry directly referenced the - // entries. - min = core.Address(ft.Field("entry").Uintptr()) - max = core.Address(ftab.SliceIndex(i + 1).Field("entry").Uintptr()) - // funcoff changed type, but had the same meaning. - funcoff = int64(ft.Field("funcoff").Uintptr()) - } + min := m.textAddr(ft.Field("entryoff").Uint32()) + max := m.textAddr(ftab.SliceIndex(i + 1).Field("entryoff").Uint32()) + funcoff := int64(ft.Field("funcoff").Uint32()) fr := pcln.SliceIndex(funcoff).Cast(rtTypeByName["runtime._func"]) var f *Func if havePCtab { @@ -83,42 +72,15 @@ // pcln must have type []byte and represent the module's pcln table region. func (m *module) readFunc(r region, pctab region, funcnametab region, rtConsts map[string]int64) *Func { f := &Func{module: m, r: r} - var nameOff int32 - switch { - case r.HasField("entryOff"): - f.entry = m.textAddr(r.Field("entryOff").Uint32()) - nameOff = r.Field("nameOff").Int32() - case r.HasField("entryoff"): - // Prior to 1.20, entryOff and nameOff were named entryoff and - // nameoff, respectively. - f.entry = m.textAddr(r.Field("entryoff").Uint32()) - nameOff = r.Field("nameoff").Int32() - default: - // Prior to 1.18, _func.entry directly referenced the entries. - f.entry = core.Address(r.Field("entry").Uintptr()) - nameOff = r.Field("nameoff").Int32() - } + f.entry = m.textAddr(r.Field("entryOff").Uint32()) + nameOff := r.Field("nameOff").Int32() f.name = r.p.ReadCString(funcnametab.SliceIndex(int64(nameOff)).a) - pcsp := r.Field("pcsp") - var pcspIdx int64 - if pcsp.typ.Kind == KindUint { - // In 1.16, pcsp changed to be a uint32 from an int32. - pcspIdx = int64(pcsp.Uint32()) - } else { - pcspIdx = int64(pcsp.Int32()) - } + pcspIdx := int64(r.Field("pcsp").Uint32()) f.frameSize.read(r.p, pctab.SliceIndex(pcspIdx).a) // Parse pcdata and funcdata, which are laid out beyond the end of the _func. - // In 1.16, npcdata changed to be a uint32 from an int32. npcdata := r.Field("npcdata") - var n uint32 - if npcdata.typ.Kind == KindUint { - // In 1.16, pcsp changed to be a uint32 from an int32. - n = npcdata.Uint32() - } else { - n = uint32(npcdata.Int32()) - } + n := npcdata.Uint32() nfd := r.Field("nfuncdata") a := nfd.a.Add(nfd.typ.Size)
diff --git a/internal/gocore/process.go b/internal/gocore/process.go index 7b2777c..fcabdc7 100644 --- a/internal/gocore/process.go +++ b/internal/gocore/process.go
@@ -17,8 +17,8 @@ "golang.org/x/debug/internal/core" - "github.com/go-delve/delve/pkg/dwarf/op" - "github.com/go-delve/delve/pkg/dwarf/regnum" + "golang.org/x/debug/third_party/delve/dwarf/op" + "golang.org/x/debug/third_party/delve/dwarf/regnum" ) // A Process represents the state of a Go process that core dumped. @@ -115,7 +115,10 @@ } } - // Read all the data that depend on runtime globals. + // Read the build version. + // + // TODO(mknyszek): Check it and reject unsupported versions. Do this once we + // feel confident which versions it actually works for. p.buildVersion = p.rtGlobals["buildVersion"].String() // Read modules and function data. @@ -403,7 +406,16 @@ // All other specials (just profile records) can't point into the heap. continue } - obj := min.Add(int64(sp.Field("offset").Uint64())) + offField := sp.Field("offset") + var off int64 + if offField.typ.Size == p.proc.PtrSize() { + // Go 1.24+ + off = int64(offField.Uintptr()) + } else { + // Go 1.23 and below. + off = int64(offField.Uint16()) + } + obj := min.Add(off) p.globals = append(p.globals, &Root{ Name: fmt.Sprintf("finalizer for %x", obj), @@ -688,6 +700,11 @@ // TODO(mknyszek): Handle composites via pieces returned by the stack program. continue } + // If the stack program indicates that there's just a single value + // in a single register, ExecuteStackProgram will return that register's + // contents. Otherwise, if it returns an address, it's referring to a + // location on the stack, which is one indirection from what we actually + // want. if addr != 0 && len(pieces) == 1 && v.typ.Kind == KindPtr { r := &Root{ Name: v.name, @@ -764,6 +781,11 @@ if addr == 0 { continue } + // If the stack program indicates that there's just a single value + // in a single register, ExecuteStackProgram will return that register's + // contents. Otherwise, if it returns an address, it's referring to a + // location on the stack, which is one indirection from what we actually + // want. if addr != 0 && len(pieces) == 1 && v.typ.Kind == KindPtr { ctxt = core.Address(addr) } else {
diff --git a/third_party/delve/LICENSE b/third_party/delve/LICENSE new file mode 100644 index 0000000..5ee9d2f --- /dev/null +++ b/third_party/delve/LICENSE
@@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Derek Parker + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/third_party/delve/README.md b/third_party/delve/README.md new file mode 100644 index 0000000..89ef824 --- /dev/null +++ b/third_party/delve/README.md
@@ -0,0 +1,7 @@ +# delve + +This is a partial import of github.com/go-delve/delve/pkg focusing +primarily on DWARF utilities. The most important part copied over is +the stack program interpreter, though the regnum package is useful too. + +Copied at commit 84c99e508c835a9b9d44bbde9558496d3583256c.
diff --git a/third_party/delve/dwarf/leb128/decode.go b/third_party/delve/dwarf/leb128/decode.go new file mode 100644 index 0000000..c066a7d --- /dev/null +++ b/third_party/delve/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(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/third_party/delve/dwarf/leb128/decode_test.go b/third_party/delve/dwarf/leb128/decode_test.go new file mode 100644 index 0000000..f9049bc --- /dev/null +++ b/third_party/delve/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/third_party/delve/dwarf/leb128/doc.go b/third_party/delve/dwarf/leb128/doc.go new file mode 100644 index 0000000..73f5a0f --- /dev/null +++ b/third_party/delve/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/third_party/delve/dwarf/leb128/encode.go b/third_party/delve/dwarf/leb128/encode.go new file mode 100644 index 0000000..c4f1a23 --- /dev/null +++ b/third_party/delve/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/third_party/delve/dwarf/leb128/encode_test.go b/third_party/delve/dwarf/leb128/encode_test.go new file mode 100644 index 0000000..f344b7c --- /dev/null +++ b/third_party/delve/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/third_party/delve/dwarf/loclist/dwarf2_loclist.go b/third_party/delve/dwarf/loclist/dwarf2_loclist.go new file mode 100644 index 0000000..8d09db6 --- /dev/null +++ b/third_party/delve/dwarf/loclist/dwarf2_loclist.go
@@ -0,0 +1,81 @@ +package loclist + +import ( + "encoding/binary" +) + +// Dwarf2Reader parses and presents DWARF loclist information for DWARF versions 2 through 4. +type Dwarf2Reader struct { + data []byte + cur int + ptrSz int +} + +// NewDwarf2Reader returns an initialized loclist Reader for DWARF versions 2 through 4. +func NewDwarf2Reader(data []byte, ptrSz int) *Dwarf2Reader { + return &Dwarf2Reader{data: data, ptrSz: ptrSz} +} + +// Empty returns true if this reader has no data. +func (rdr *Dwarf2Reader) Empty() bool { + return rdr.data == nil +} + +// Seek moves the data pointer to the specified offset. +func (rdr *Dwarf2Reader) Seek(off int) { + rdr.cur = off +} + +// Next advances the reader to the next loclist entry, returning +// the entry and true if successful, or nil, false if not. +func (rdr *Dwarf2Reader) Next(e *Entry) bool { + e.LowPC = rdr.oneAddr() + e.HighPC = rdr.oneAddr() + + if e.LowPC == 0 && e.HighPC == 0 { + return false + } + + if e.BaseAddressSelection() { + e.Instr = nil + return true + } + + instrlen := binary.LittleEndian.Uint16(rdr.read(2)) + e.Instr = rdr.read(int(instrlen)) + return true +} + +func (rdr *Dwarf2Reader) read(sz int) []byte { + r := rdr.data[rdr.cur : rdr.cur+sz] + rdr.cur += sz + return r +} + +func (rdr *Dwarf2Reader) oneAddr() uint64 { + switch rdr.ptrSz { + case 4: + addr := binary.LittleEndian.Uint32(rdr.read(rdr.ptrSz)) + if addr == ^uint32(0) { + return ^uint64(0) + } + return uint64(addr) + case 8: + addr := binary.LittleEndian.Uint64(rdr.read(rdr.ptrSz)) + return addr + default: + panic("bad address size") + } +} + +// Entry represents a single entry in the loclist section. +type Entry struct { + LowPC, HighPC uint64 + Instr []byte +} + +// BaseAddressSelection returns true if entry.highpc should +// be used as the base address for subsequent entries. +func (e *Entry) BaseAddressSelection() bool { + return e.LowPC == ^uint64(0) +}
diff --git a/third_party/delve/dwarf/op/op.go b/third_party/delve/dwarf/op/op.go new file mode 100644 index 0000000..402ffef --- /dev/null +++ b/third_party/delve/dwarf/op/op.go
@@ -0,0 +1,573 @@ +package op + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + + "golang.org/x/debug/third_party/delve/dwarf" + "golang.org/x/debug/third_party/delve/dwarf/leb128" +) + +// Opcode represent a DWARF stack program instruction. +// See ./opcodes.go for a full list. +type Opcode byte + +//go:generate go run ../../../_scripts/gen-opcodes.go opcodes.table opcodes.go + +type stackfn func(Opcode, *context) error + +type ReadMemoryFunc func([]byte, uint64) (int, error) + +type context struct { + buf *bytes.Buffer + prog []byte + stack []int64 + pieces []Piece + ptrSize int + + DwarfRegisters + readMemory ReadMemoryFunc +} + +// Piece is a piece of memory stored either at an address or in a register. +type Piece struct { + Size int + Kind PieceKind + Val uint64 + Bytes []byte +} + +// PieceKind describes the kind of a piece. +type PieceKind uint8 + +const ( + AddrPiece PieceKind = iota // The piece is stored in memory, Val is the address + RegPiece // The piece is stored in a register, Val is the register number + ImmPiece // The piece is an immediate value, Val or Bytes is the value +) + +var ( + ErrStackUnderflow = errors.New("DWARF stack underflow") + ErrStackIndexOutOfBounds = errors.New("DWARF stack index out of bounds") + ErrMemoryReadUnavailable = errors.New("memory read unavailable") +) + +const arbitraryExecutionLimitFactor = 10 + +// ExecuteStackProgram executes a DWARF location expression and returns +// either an address (int64), or a slice of Pieces for location expressions +// that don't evaluate to an address (such as register and composite expressions). +func ExecuteStackProgram(regs DwarfRegisters, instructions []byte, ptrSize int, readMemory ReadMemoryFunc) (int64, []Piece, error) { + ctxt := &context{ + buf: bytes.NewBuffer(instructions), + prog: instructions, + stack: make([]int64, 0, 3), + DwarfRegisters: regs, + ptrSize: ptrSize, + readMemory: readMemory, + } + + for tick := 0; tick < len(instructions)*arbitraryExecutionLimitFactor; tick++ { + opcodeByte, err := ctxt.buf.ReadByte() + if err != nil { + break + } + opcode := Opcode(opcodeByte) + if opcode == DW_OP_nop { + continue + } + fn, ok := oplut[opcode] + if !ok { + return 0, nil, fmt.Errorf("invalid instruction %#v", opcode) + } + + err = fn(opcode, ctxt) + if err != nil { + return 0, nil, err + } + } + + if ctxt.pieces != nil { + if len(ctxt.pieces) == 1 && ctxt.pieces[0].Kind == RegPiece { + return int64(regs.Uint64Val(ctxt.pieces[0].Val)), ctxt.pieces, nil + } + return 0, ctxt.pieces, nil + } + + if len(ctxt.stack) == 0 { + return 0, nil, errors.New("empty OP stack") + } + + return ctxt.stack[len(ctxt.stack)-1], nil, nil +} + +// PrettyPrint prints the DWARF stack program instructions to `out`. +func PrettyPrint(out io.Writer, instructions []byte, regnumToName func(uint64) string) { + in := bytes.NewBuffer(instructions) + + for { + opcode, err := in.ReadByte() + if err != nil { + break + } + op := Opcode(opcode) + if name, hasname := opcodeName[op]; hasname { + io.WriteString(out, name) + if regnumToName != nil { + if op >= DW_OP_reg0 && op <= DW_OP_reg31 { + fmt.Fprintf(out, "(%s)", regnumToName(uint64(op-DW_OP_reg0))) + } else if op >= DW_OP_breg0 && op <= DW_OP_breg31 { + fmt.Fprintf(out, "(%s)", regnumToName(uint64(op-DW_OP_breg0))) + } + } + out.Write([]byte{' '}) + } else { + fmt.Fprintf(out, "%#x ", opcode) + } + + for i, arg := range opcodeArgs[Opcode(opcode)] { + var regnum uint64 + switch arg { + case 's': + n, _ := leb128.DecodeSigned(in) + regnum = uint64(n) + fmt.Fprintf(out, "%#x ", n) + case 'u': + n, _ := leb128.DecodeUnsigned(in) + regnum = n + fmt.Fprintf(out, "%#x ", n) + case '1': + var x uint8 + binary.Read(in, binary.LittleEndian, &x) + fmt.Fprintf(out, "%#x ", x) + case '2': + var x uint16 + binary.Read(in, binary.LittleEndian, &x) + fmt.Fprintf(out, "%#x ", x) + case '4': + var x uint32 + binary.Read(in, binary.LittleEndian, &x) + fmt.Fprintf(out, "%#x ", x) + case '8': + var x uint64 + binary.Read(in, binary.LittleEndian, &x) + fmt.Fprintf(out, "%#x ", x) + case 'B': + sz, _ := leb128.DecodeUnsigned(in) + data := make([]byte, sz) + sz2, _ := in.Read(data) + data = data[:sz2] + fmt.Fprintf(out, "%d [%x] ", sz, data) + } + if regnumToName != nil && i == 0 && (op == DW_OP_regx || op == DW_OP_bregx) { + fmt.Fprintf(out, "(%s)", regnumToName(regnum)) + } + } + } +} + +// closeLoc is called by opcodes that can only appear at the end of a +// location expression (DW_OP_regN, DW_OP_regx, DW_OP_stack_value...). +// It checks that we are at the end of the program or that the following +// opcode is DW_OP_piece or DW_OP_bit_piece and processes them. +func (ctxt *context) closeLoc(opcode0 Opcode, piece Piece) error { + if ctxt.buf.Len() == 0 { + ctxt.pieces = append(ctxt.pieces, piece) + return nil + } + + // DWARF doesn't say what happens to the operand stack at the end of a + // location expression, resetting it here. + ctxt.stack = ctxt.stack[:0] + + b, err := ctxt.buf.ReadByte() + if err != nil { + return err + } + opcode := Opcode(b) + + switch opcode { + case DW_OP_piece: + sz, _ := leb128.DecodeUnsigned(ctxt.buf) + piece.Size = int(sz) + ctxt.pieces = append(ctxt.pieces, piece) + return nil + + case DW_OP_bit_piece: + // not supported + return fmt.Errorf("invalid instruction %#v", opcode) + default: + return fmt.Errorf("invalid instruction %#v after %#v", opcode, opcode0) + } +} + +func callframecfa(opcode Opcode, ctxt *context) error { + if ctxt.CFA == 0 { + return errors.New("could not retrieve CFA for current PC") + } + ctxt.stack = append(ctxt.stack, ctxt.CFA) + return nil +} + +func addr(opcode Opcode, ctxt *context) error { + buf := ctxt.buf.Next(ctxt.ptrSize) + stack, err := dwarf.ReadUintRaw(bytes.NewReader(buf), binary.LittleEndian, ctxt.ptrSize) + if err != nil { + return err + } + ctxt.stack = append(ctxt.stack, int64(stack+ctxt.StaticBase)) + return nil +} + +func plusuconsts(opcode Opcode, ctxt *context) error { + slen := len(ctxt.stack) + 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, _ := leb128.DecodeSigned(ctxt.buf) + ctxt.stack = append(ctxt.stack, num) + return nil +} + +func framebase(opcode Opcode, ctxt *context) error { + num, _ := leb128.DecodeSigned(ctxt.buf) + ctxt.stack = append(ctxt.stack, ctxt.FrameBase+num) + return nil +} + +func register(opcode Opcode, ctxt *context) error { + var regnum uint64 + if opcode == DW_OP_regx { + regnum, _ = leb128.DecodeUnsigned(ctxt.buf) + } else { + regnum = uint64(opcode - DW_OP_reg0) + } + return ctxt.closeLoc(opcode, Piece{Kind: RegPiece, Val: regnum}) +} + +func bregister(opcode Opcode, ctxt *context) error { + var regnum uint64 + if opcode == DW_OP_bregx { + regnum, _ = leb128.DecodeUnsigned(ctxt.buf) + } else { + regnum = uint64(opcode - DW_OP_breg0) + } + offset, _ := leb128.DecodeSigned(ctxt.buf) + if ctxt.Reg(regnum) == nil { + return fmt.Errorf("register %d not available", regnum) + } + ctxt.stack = append(ctxt.stack, int64(ctxt.Uint64Val(regnum))+offset) + return nil +} + +func piece(opcode Opcode, ctxt *context) error { + sz, _ := leb128.DecodeUnsigned(ctxt.buf) + + if len(ctxt.stack) == 0 { + // nothing on the stack means this piece is unavailable (padding, + // optimized away...), see DWARFv4 sec. 2.6.1.3 page 30. + ctxt.pieces = append(ctxt.pieces, Piece{Size: int(sz), Kind: ImmPiece, Val: 0}) + return nil + } + + addr := ctxt.stack[len(ctxt.stack)-1] + ctxt.pieces = append(ctxt.pieces, Piece{Size: int(sz), Kind: AddrPiece, Val: uint64(addr)}) + ctxt.stack = ctxt.stack[:0] + return nil +} + +func literal(opcode Opcode, ctxt *context) error { + ctxt.stack = append(ctxt.stack, int64(opcode-DW_OP_lit0)) + return nil +} + +func constnu(opcode Opcode, ctxt *context) error { + var ( + n uint64 + err error + ) + switch opcode { + case DW_OP_const1u: + var b uint8 + b, err = ctxt.buf.ReadByte() + n = uint64(b) + case DW_OP_const2u: + n, err = dwarf.ReadUintRaw(ctxt.buf, binary.LittleEndian, 2) + case DW_OP_const4u: + n, err = dwarf.ReadUintRaw(ctxt.buf, binary.LittleEndian, 4) + case DW_OP_const8u: + n, err = dwarf.ReadUintRaw(ctxt.buf, binary.LittleEndian, 8) + default: + panic("internal error") + } + if err != nil { + return err + } + ctxt.stack = append(ctxt.stack, int64(n)) + return nil +} + +func constns(opcode Opcode, ctxt *context) error { + var ( + n uint64 + err error + ) + switch opcode { + case DW_OP_const1s: + var b uint8 + b, err = ctxt.buf.ReadByte() + n = uint64(int64(int8(b))) + case DW_OP_const2s: + n, err = dwarf.ReadUintRaw(ctxt.buf, binary.LittleEndian, 2) + n = uint64(int64(int16(n))) + case DW_OP_const4s: + n, err = dwarf.ReadUintRaw(ctxt.buf, binary.LittleEndian, 4) + n = uint64(int64(int32(n))) + case DW_OP_const8s: + n, err = dwarf.ReadUintRaw(ctxt.buf, binary.LittleEndian, 8) + default: + panic("internal error") + } + if err != nil { + return err + } + ctxt.stack = append(ctxt.stack, int64(n)) + return nil +} + +func constu(opcode Opcode, ctxt *context) error { + num, _ := leb128.DecodeUnsigned(ctxt.buf) + ctxt.stack = append(ctxt.stack, int64(num)) + return nil +} + +func dup(_ Opcode, ctxt *context) error { + if len(ctxt.stack) == 0 { + return ErrStackUnderflow + } + ctxt.stack = append(ctxt.stack, ctxt.stack[len(ctxt.stack)-1]) + return nil +} + +func drop(_ Opcode, ctxt *context) error { + if len(ctxt.stack) == 0 { + return ErrStackUnderflow + } + ctxt.stack = ctxt.stack[:len(ctxt.stack)-1] + return nil +} + +func pick(opcode Opcode, ctxt *context) error { + var n byte + switch opcode { + case DW_OP_pick: + n, _ = ctxt.buf.ReadByte() + case DW_OP_over: + n = 1 + default: + panic("internal error") + } + idx := len(ctxt.stack) - 1 - int(n) + if idx < 0 || idx >= len(ctxt.stack) { + return ErrStackIndexOutOfBounds + } + ctxt.stack = append(ctxt.stack, ctxt.stack[idx]) + return nil +} + +func swap(_ Opcode, ctxt *context) error { + if len(ctxt.stack) < 2 { + return ErrStackUnderflow + } + ctxt.stack[len(ctxt.stack)-1], ctxt.stack[len(ctxt.stack)-2] = ctxt.stack[len(ctxt.stack)-2], ctxt.stack[len(ctxt.stack)-1] + return nil +} + +func rot(_ Opcode, ctxt *context) error { + if len(ctxt.stack) < 3 { + return ErrStackUnderflow + } + ctxt.stack[len(ctxt.stack)-1], ctxt.stack[len(ctxt.stack)-2], ctxt.stack[len(ctxt.stack)-3] = ctxt.stack[len(ctxt.stack)-2], ctxt.stack[len(ctxt.stack)-3], ctxt.stack[len(ctxt.stack)-1] + return nil +} + +func unaryop(opcode Opcode, ctxt *context) error { + if len(ctxt.stack) < 1 { + return ErrStackUnderflow + } + operand := ctxt.stack[len(ctxt.stack)-1] + switch opcode { + case DW_OP_abs: + if operand < 0 { + operand = -operand + } + case DW_OP_neg: + operand = -operand + case DW_OP_not: + operand = ^operand + default: + panic("internal error") + } + ctxt.stack[len(ctxt.stack)-1] = operand + return nil +} + +func binaryop(opcode Opcode, ctxt *context) error { + if len(ctxt.stack) < 2 { + return ErrStackUnderflow + } + second := ctxt.stack[len(ctxt.stack)-2] + top := ctxt.stack[len(ctxt.stack)-1] + var r int64 + ctxt.stack = ctxt.stack[:len(ctxt.stack)-2] + switch opcode { + case DW_OP_and: + r = second & top + case DW_OP_div: + r = second / top + case DW_OP_minus: + r = second - top + case DW_OP_mod: + r = second % top + case DW_OP_mul: + r = second * top + case DW_OP_or: + r = second | top + case DW_OP_plus: + r = second + top + case DW_OP_shl: + r = second << uint64(top) + case DW_OP_shr: + r = second >> uint64(top) + case DW_OP_shra: + r = int64(uint64(second) >> uint64(top)) + case DW_OP_xor: + r = second ^ top + case DW_OP_le: + r = bool2int(second <= top) + case DW_OP_ge: + r = bool2int(second >= top) + case DW_OP_eq: + r = bool2int(second == top) + case DW_OP_lt: + r = bool2int(second < top) + case DW_OP_gt: + r = bool2int(second > top) + case DW_OP_ne: + r = bool2int(second != top) + default: + panic("internal error") + } + ctxt.stack = append(ctxt.stack, r) + return nil +} + +func bool2int(b bool) int64 { + if b { + return 1 + } + return 0 +} + +func (ctxt *context) jump(n int16) error { + i := len(ctxt.prog) - ctxt.buf.Len() + int(n) + if i < 0 { + return ErrStackUnderflow + } + if i >= len(ctxt.prog) { + i = len(ctxt.prog) + } + ctxt.buf = bytes.NewBuffer(ctxt.prog[i:]) + return nil +} + +func skip(_ Opcode, ctxt *context) error { + var n int16 + binary.Read(ctxt.buf, binary.LittleEndian, &n) + return ctxt.jump(n) +} + +func bra(_ Opcode, ctxt *context) error { + var n int16 + binary.Read(ctxt.buf, binary.LittleEndian, &n) + + if len(ctxt.stack) < 1 { + return ErrStackUnderflow + } + top := ctxt.stack[len(ctxt.stack)-1] + ctxt.stack = ctxt.stack[:len(ctxt.stack)-1] + if top != 0 { + return ctxt.jump(n) + } + return nil +} + +func stackvalue(_ Opcode, ctxt *context) error { + if len(ctxt.stack) < 1 { + return ErrStackUnderflow + } + val := ctxt.stack[len(ctxt.stack)-1] + ctxt.stack = ctxt.stack[:len(ctxt.stack)-1] + return ctxt.closeLoc(DW_OP_stack_value, Piece{Kind: ImmPiece, Val: uint64(val)}) +} + +func implicitvalue(_ Opcode, ctxt *context) error { + sz, _ := leb128.DecodeUnsigned(ctxt.buf) + block := make([]byte, sz) + n, _ := ctxt.buf.Read(block) + if uint64(n) != sz { + return fmt.Errorf("insufficient bytes read while reading DW_OP_implicit_value's block %d (expected: %d)", n, sz) + } + return ctxt.closeLoc(DW_OP_implicit_value, Piece{Kind: ImmPiece, Bytes: block, Size: int(sz)}) +} + +func deref(op Opcode, ctxt *context) error { + if ctxt.readMemory == nil { + return ErrMemoryReadUnavailable + } + + sz := ctxt.ptrSize + if op == DW_OP_deref_size || op == DW_OP_xderef_size { + n, err := ctxt.buf.ReadByte() + if err != nil { + return err + } + sz = int(n) + } + + if len(ctxt.stack) == 0 { + return ErrStackUnderflow + } + + addr := ctxt.stack[len(ctxt.stack)-1] + ctxt.stack = ctxt.stack[:len(ctxt.stack)-1] + + if op == DW_OP_xderef || op == DW_OP_xderef_size { + if len(ctxt.stack) == 0 { + return ErrStackUnderflow + } + // the second element on the stack is the "address space identifier" which we don't do anything with + ctxt.stack = ctxt.stack[:len(ctxt.stack)-1] + } + + buf := make([]byte, sz) + _, err := ctxt.readMemory(buf, uint64(addr)) + if err != nil { + return err + } + + x, err := dwarf.ReadUintRaw(bytes.NewReader(buf), binary.LittleEndian, sz) + if err != nil { + return err + } + + ctxt.stack = append(ctxt.stack, int64(x)) + + return nil +}
diff --git a/third_party/delve/dwarf/op/op_test.go b/third_party/delve/dwarf/op/op_test.go new file mode 100644 index 0000000..92927e0 --- /dev/null +++ b/third_party/delve/dwarf/op/op_test.go
@@ -0,0 +1,58 @@ +package op + +import ( + "strings" + "testing" +) + +func assertExprResult(t *testing.T, expected int64, instructions []byte) { + t.Helper() + actual, _, err := ExecuteStackProgram(DwarfRegisters{}, instructions, 8, nil) + if err != nil { + t.Error(err) + } + if actual != expected { + buf := new(strings.Builder) + PrettyPrint(buf, instructions, nil) + t.Errorf("actual %d != expected %d (in %s)", actual, expected, buf.String()) + } +} + +func TestExecuteStackProgram(t *testing.T) { + assertExprResult(t, 56, []byte{byte(DW_OP_consts), 0x1c, byte(DW_OP_consts), 0x1c, byte(DW_OP_plus)}) +} + +func TestSignExtension(t *testing.T) { + var tgt uint64 = 0xffffffffffffff88 + assertExprResult(t, int64(tgt), []byte{byte(DW_OP_const1s), 0x88}) + tgt = 0xffffffffffff8888 + assertExprResult(t, int64(tgt), []byte{byte(DW_OP_const2s), 0x88, 0x88}) +} + +func TestStackOps(t *testing.T) { + assertExprResult(t, 1, []byte{byte(DW_OP_lit1), byte(DW_OP_lit2), byte(DW_OP_drop)}) + assertExprResult(t, 0, []byte{byte(DW_OP_lit1), byte(DW_OP_lit0), byte(DW_OP_pick), 0}) + assertExprResult(t, 1, []byte{byte(DW_OP_lit1), byte(DW_OP_lit0), byte(DW_OP_pick), 1}) +} + +func TestBra(t *testing.T) { + assertExprResult(t, 32, []byte{ + byte(DW_OP_lit1), + byte(DW_OP_lit5), + + byte(DW_OP_dup), + byte(DW_OP_lit0), + byte(DW_OP_eq), + byte(DW_OP_bra), 9, 0x0, + + byte(DW_OP_swap), + byte(DW_OP_dup), + byte(DW_OP_plus), + byte(DW_OP_swap), + byte(DW_OP_lit1), + byte(DW_OP_minus), + byte(DW_OP_skip), 0xf1, 0xff, + + byte(DW_OP_drop), + }) +}
diff --git a/third_party/delve/dwarf/op/opcodes.go b/third_party/delve/dwarf/op/opcodes.go new file mode 100644 index 0000000..5a5643a --- /dev/null +++ b/third_party/delve/dwarf/op/opcodes.go
@@ -0,0 +1,623 @@ +// Code generated by gen-opcodes. DO NOT EDIT. +// Edit opcodes.table instead. + +package op + +const ( + DW_OP_addr Opcode = 0x03 + DW_OP_deref Opcode = 0x06 + DW_OP_const1u Opcode = 0x08 + DW_OP_const1s Opcode = 0x09 + DW_OP_const2u Opcode = 0x0a + DW_OP_const2s Opcode = 0x0b + DW_OP_const4u Opcode = 0x0c + DW_OP_const4s Opcode = 0x0d + DW_OP_const8u Opcode = 0x0e + DW_OP_const8s Opcode = 0x0f + DW_OP_constu Opcode = 0x10 + DW_OP_consts Opcode = 0x11 + DW_OP_dup Opcode = 0x12 + DW_OP_drop Opcode = 0x13 + DW_OP_over Opcode = 0x14 + DW_OP_pick Opcode = 0x15 + DW_OP_swap Opcode = 0x16 + DW_OP_rot Opcode = 0x17 + DW_OP_xderef Opcode = 0x18 + DW_OP_abs Opcode = 0x19 + DW_OP_and Opcode = 0x1a + DW_OP_div Opcode = 0x1b + DW_OP_minus Opcode = 0x1c + DW_OP_mod Opcode = 0x1d + DW_OP_mul Opcode = 0x1e + DW_OP_neg Opcode = 0x1f + DW_OP_not Opcode = 0x20 + DW_OP_or Opcode = 0x21 + DW_OP_plus Opcode = 0x22 + DW_OP_plus_uconst Opcode = 0x23 + DW_OP_shl Opcode = 0x24 + DW_OP_shr Opcode = 0x25 + DW_OP_shra Opcode = 0x26 + DW_OP_xor Opcode = 0x27 + DW_OP_bra Opcode = 0x28 + DW_OP_eq Opcode = 0x29 + DW_OP_ge Opcode = 0x2a + DW_OP_gt Opcode = 0x2b + DW_OP_le Opcode = 0x2c + DW_OP_lt Opcode = 0x2d + DW_OP_ne Opcode = 0x2e + DW_OP_skip Opcode = 0x2f + DW_OP_lit0 Opcode = 0x30 + DW_OP_lit1 Opcode = 0x31 + DW_OP_lit2 Opcode = 0x32 + DW_OP_lit3 Opcode = 0x33 + DW_OP_lit4 Opcode = 0x34 + DW_OP_lit5 Opcode = 0x35 + DW_OP_lit6 Opcode = 0x36 + DW_OP_lit7 Opcode = 0x37 + DW_OP_lit8 Opcode = 0x38 + DW_OP_lit9 Opcode = 0x39 + DW_OP_lit10 Opcode = 0x3a + DW_OP_lit11 Opcode = 0x3b + DW_OP_lit12 Opcode = 0x3c + DW_OP_lit13 Opcode = 0x3d + DW_OP_lit14 Opcode = 0x3e + DW_OP_lit15 Opcode = 0x3f + DW_OP_lit16 Opcode = 0x40 + DW_OP_lit17 Opcode = 0x41 + DW_OP_lit18 Opcode = 0x42 + DW_OP_lit19 Opcode = 0x43 + DW_OP_lit20 Opcode = 0x44 + DW_OP_lit21 Opcode = 0x45 + DW_OP_lit22 Opcode = 0x46 + DW_OP_lit23 Opcode = 0x47 + DW_OP_lit24 Opcode = 0x48 + DW_OP_lit25 Opcode = 0x49 + DW_OP_lit26 Opcode = 0x4a + DW_OP_lit27 Opcode = 0x4b + DW_OP_lit28 Opcode = 0x4c + DW_OP_lit29 Opcode = 0x4d + DW_OP_lit30 Opcode = 0x4e + DW_OP_lit31 Opcode = 0x4f + DW_OP_reg0 Opcode = 0x50 + DW_OP_reg1 Opcode = 0x51 + DW_OP_reg2 Opcode = 0x52 + DW_OP_reg3 Opcode = 0x53 + DW_OP_reg4 Opcode = 0x54 + DW_OP_reg5 Opcode = 0x55 + DW_OP_reg6 Opcode = 0x56 + DW_OP_reg7 Opcode = 0x57 + DW_OP_reg8 Opcode = 0x58 + DW_OP_reg9 Opcode = 0x59 + DW_OP_reg10 Opcode = 0x5a + DW_OP_reg11 Opcode = 0x5b + DW_OP_reg12 Opcode = 0x5c + DW_OP_reg13 Opcode = 0x5d + DW_OP_reg14 Opcode = 0x5e + DW_OP_reg15 Opcode = 0x5f + DW_OP_reg16 Opcode = 0x60 + DW_OP_reg17 Opcode = 0x61 + DW_OP_reg18 Opcode = 0x62 + DW_OP_reg19 Opcode = 0x63 + DW_OP_reg20 Opcode = 0x64 + DW_OP_reg21 Opcode = 0x65 + DW_OP_reg22 Opcode = 0x66 + DW_OP_reg23 Opcode = 0x67 + DW_OP_reg24 Opcode = 0x68 + DW_OP_reg25 Opcode = 0x69 + DW_OP_reg26 Opcode = 0x6a + DW_OP_reg27 Opcode = 0x6b + DW_OP_reg28 Opcode = 0x6c + DW_OP_reg29 Opcode = 0x6d + DW_OP_reg30 Opcode = 0x6e + DW_OP_reg31 Opcode = 0x6f + DW_OP_breg0 Opcode = 0x70 + DW_OP_breg1 Opcode = 0x71 + DW_OP_breg2 Opcode = 0x72 + DW_OP_breg3 Opcode = 0x73 + DW_OP_breg4 Opcode = 0x74 + DW_OP_breg5 Opcode = 0x75 + DW_OP_breg6 Opcode = 0x76 + DW_OP_breg7 Opcode = 0x77 + DW_OP_breg8 Opcode = 0x78 + DW_OP_breg9 Opcode = 0x79 + DW_OP_breg10 Opcode = 0x7a + DW_OP_breg11 Opcode = 0x7b + DW_OP_breg12 Opcode = 0x7c + DW_OP_breg13 Opcode = 0x7d + DW_OP_breg14 Opcode = 0x7e + DW_OP_breg15 Opcode = 0x7f + DW_OP_breg16 Opcode = 0x80 + DW_OP_breg17 Opcode = 0x81 + DW_OP_breg18 Opcode = 0x82 + DW_OP_breg19 Opcode = 0x83 + DW_OP_breg20 Opcode = 0x84 + DW_OP_breg21 Opcode = 0x85 + DW_OP_breg22 Opcode = 0x86 + DW_OP_breg23 Opcode = 0x87 + DW_OP_breg24 Opcode = 0x88 + DW_OP_breg25 Opcode = 0x89 + DW_OP_breg26 Opcode = 0x8a + DW_OP_breg27 Opcode = 0x8b + DW_OP_breg28 Opcode = 0x8c + DW_OP_breg29 Opcode = 0x8d + DW_OP_breg30 Opcode = 0x8e + DW_OP_breg31 Opcode = 0x8f + DW_OP_regx Opcode = 0x90 + DW_OP_fbreg Opcode = 0x91 + DW_OP_bregx Opcode = 0x92 + DW_OP_piece Opcode = 0x93 + DW_OP_deref_size Opcode = 0x94 + DW_OP_xderef_size Opcode = 0x95 + DW_OP_nop Opcode = 0x96 + DW_OP_push_object_address Opcode = 0x97 + DW_OP_call2 Opcode = 0x98 + DW_OP_call4 Opcode = 0x99 + DW_OP_call_ref Opcode = 0x9a + DW_OP_form_tls_address Opcode = 0x9b + DW_OP_call_frame_cfa Opcode = 0x9c + DW_OP_bit_piece Opcode = 0x9d + DW_OP_implicit_value Opcode = 0x9e + DW_OP_stack_value Opcode = 0x9f +) + +var opcodeName = map[Opcode]string{ + DW_OP_addr: "DW_OP_addr", + DW_OP_deref: "DW_OP_deref", + DW_OP_const1u: "DW_OP_const1u", + DW_OP_const1s: "DW_OP_const1s", + DW_OP_const2u: "DW_OP_const2u", + DW_OP_const2s: "DW_OP_const2s", + DW_OP_const4u: "DW_OP_const4u", + DW_OP_const4s: "DW_OP_const4s", + DW_OP_const8u: "DW_OP_const8u", + DW_OP_const8s: "DW_OP_const8s", + DW_OP_constu: "DW_OP_constu", + DW_OP_consts: "DW_OP_consts", + DW_OP_dup: "DW_OP_dup", + DW_OP_drop: "DW_OP_drop", + DW_OP_over: "DW_OP_over", + DW_OP_pick: "DW_OP_pick", + DW_OP_swap: "DW_OP_swap", + DW_OP_rot: "DW_OP_rot", + DW_OP_xderef: "DW_OP_xderef", + DW_OP_abs: "DW_OP_abs", + DW_OP_and: "DW_OP_and", + DW_OP_div: "DW_OP_div", + DW_OP_minus: "DW_OP_minus", + DW_OP_mod: "DW_OP_mod", + DW_OP_mul: "DW_OP_mul", + DW_OP_neg: "DW_OP_neg", + DW_OP_not: "DW_OP_not", + DW_OP_or: "DW_OP_or", + DW_OP_plus: "DW_OP_plus", + DW_OP_plus_uconst: "DW_OP_plus_uconst", + DW_OP_shl: "DW_OP_shl", + DW_OP_shr: "DW_OP_shr", + DW_OP_shra: "DW_OP_shra", + DW_OP_xor: "DW_OP_xor", + DW_OP_bra: "DW_OP_bra", + DW_OP_eq: "DW_OP_eq", + DW_OP_ge: "DW_OP_ge", + DW_OP_gt: "DW_OP_gt", + DW_OP_le: "DW_OP_le", + DW_OP_lt: "DW_OP_lt", + DW_OP_ne: "DW_OP_ne", + DW_OP_skip: "DW_OP_skip", + DW_OP_lit0: "DW_OP_lit0", + DW_OP_lit1: "DW_OP_lit1", + DW_OP_lit2: "DW_OP_lit2", + DW_OP_lit3: "DW_OP_lit3", + DW_OP_lit4: "DW_OP_lit4", + DW_OP_lit5: "DW_OP_lit5", + DW_OP_lit6: "DW_OP_lit6", + DW_OP_lit7: "DW_OP_lit7", + DW_OP_lit8: "DW_OP_lit8", + DW_OP_lit9: "DW_OP_lit9", + DW_OP_lit10: "DW_OP_lit10", + DW_OP_lit11: "DW_OP_lit11", + DW_OP_lit12: "DW_OP_lit12", + DW_OP_lit13: "DW_OP_lit13", + DW_OP_lit14: "DW_OP_lit14", + DW_OP_lit15: "DW_OP_lit15", + DW_OP_lit16: "DW_OP_lit16", + DW_OP_lit17: "DW_OP_lit17", + DW_OP_lit18: "DW_OP_lit18", + DW_OP_lit19: "DW_OP_lit19", + DW_OP_lit20: "DW_OP_lit20", + DW_OP_lit21: "DW_OP_lit21", + DW_OP_lit22: "DW_OP_lit22", + DW_OP_lit23: "DW_OP_lit23", + DW_OP_lit24: "DW_OP_lit24", + DW_OP_lit25: "DW_OP_lit25", + DW_OP_lit26: "DW_OP_lit26", + DW_OP_lit27: "DW_OP_lit27", + DW_OP_lit28: "DW_OP_lit28", + DW_OP_lit29: "DW_OP_lit29", + DW_OP_lit30: "DW_OP_lit30", + DW_OP_lit31: "DW_OP_lit31", + DW_OP_reg0: "DW_OP_reg0", + DW_OP_reg1: "DW_OP_reg1", + DW_OP_reg2: "DW_OP_reg2", + DW_OP_reg3: "DW_OP_reg3", + DW_OP_reg4: "DW_OP_reg4", + DW_OP_reg5: "DW_OP_reg5", + DW_OP_reg6: "DW_OP_reg6", + DW_OP_reg7: "DW_OP_reg7", + DW_OP_reg8: "DW_OP_reg8", + DW_OP_reg9: "DW_OP_reg9", + DW_OP_reg10: "DW_OP_reg10", + DW_OP_reg11: "DW_OP_reg11", + DW_OP_reg12: "DW_OP_reg12", + DW_OP_reg13: "DW_OP_reg13", + DW_OP_reg14: "DW_OP_reg14", + DW_OP_reg15: "DW_OP_reg15", + DW_OP_reg16: "DW_OP_reg16", + DW_OP_reg17: "DW_OP_reg17", + DW_OP_reg18: "DW_OP_reg18", + DW_OP_reg19: "DW_OP_reg19", + DW_OP_reg20: "DW_OP_reg20", + DW_OP_reg21: "DW_OP_reg21", + DW_OP_reg22: "DW_OP_reg22", + DW_OP_reg23: "DW_OP_reg23", + DW_OP_reg24: "DW_OP_reg24", + DW_OP_reg25: "DW_OP_reg25", + DW_OP_reg26: "DW_OP_reg26", + DW_OP_reg27: "DW_OP_reg27", + DW_OP_reg28: "DW_OP_reg28", + DW_OP_reg29: "DW_OP_reg29", + DW_OP_reg30: "DW_OP_reg30", + DW_OP_reg31: "DW_OP_reg31", + DW_OP_breg0: "DW_OP_breg0", + DW_OP_breg1: "DW_OP_breg1", + DW_OP_breg2: "DW_OP_breg2", + DW_OP_breg3: "DW_OP_breg3", + DW_OP_breg4: "DW_OP_breg4", + DW_OP_breg5: "DW_OP_breg5", + DW_OP_breg6: "DW_OP_breg6", + DW_OP_breg7: "DW_OP_breg7", + DW_OP_breg8: "DW_OP_breg8", + DW_OP_breg9: "DW_OP_breg9", + DW_OP_breg10: "DW_OP_breg10", + DW_OP_breg11: "DW_OP_breg11", + DW_OP_breg12: "DW_OP_breg12", + DW_OP_breg13: "DW_OP_breg13", + DW_OP_breg14: "DW_OP_breg14", + DW_OP_breg15: "DW_OP_breg15", + DW_OP_breg16: "DW_OP_breg16", + DW_OP_breg17: "DW_OP_breg17", + DW_OP_breg18: "DW_OP_breg18", + DW_OP_breg19: "DW_OP_breg19", + DW_OP_breg20: "DW_OP_breg20", + DW_OP_breg21: "DW_OP_breg21", + DW_OP_breg22: "DW_OP_breg22", + DW_OP_breg23: "DW_OP_breg23", + DW_OP_breg24: "DW_OP_breg24", + DW_OP_breg25: "DW_OP_breg25", + DW_OP_breg26: "DW_OP_breg26", + DW_OP_breg27: "DW_OP_breg27", + DW_OP_breg28: "DW_OP_breg28", + DW_OP_breg29: "DW_OP_breg29", + DW_OP_breg30: "DW_OP_breg30", + DW_OP_breg31: "DW_OP_breg31", + DW_OP_regx: "DW_OP_regx", + DW_OP_fbreg: "DW_OP_fbreg", + DW_OP_bregx: "DW_OP_bregx", + DW_OP_piece: "DW_OP_piece", + DW_OP_deref_size: "DW_OP_deref_size", + DW_OP_xderef_size: "DW_OP_xderef_size", + DW_OP_nop: "DW_OP_nop", + DW_OP_push_object_address: "DW_OP_push_object_address", + DW_OP_call2: "DW_OP_call2", + DW_OP_call4: "DW_OP_call4", + DW_OP_call_ref: "DW_OP_call_ref", + DW_OP_form_tls_address: "DW_OP_form_tls_address", + DW_OP_call_frame_cfa: "DW_OP_call_frame_cfa", + DW_OP_bit_piece: "DW_OP_bit_piece", + DW_OP_implicit_value: "DW_OP_implicit_value", + DW_OP_stack_value: "DW_OP_stack_value", +} +var opcodeArgs = map[Opcode]string{ + DW_OP_addr: "8", + DW_OP_deref: "", + DW_OP_const1u: "1", + DW_OP_const1s: "1", + DW_OP_const2u: "2", + DW_OP_const2s: "2", + DW_OP_const4u: "4", + DW_OP_const4s: "4", + DW_OP_const8u: "8", + DW_OP_const8s: "8", + DW_OP_constu: "u", + DW_OP_consts: "s", + DW_OP_dup: "", + DW_OP_drop: "", + DW_OP_over: "", + DW_OP_pick: "", + DW_OP_swap: "", + DW_OP_rot: "", + DW_OP_xderef: "", + DW_OP_abs: "", + DW_OP_and: "", + DW_OP_div: "", + DW_OP_minus: "", + DW_OP_mod: "", + DW_OP_mul: "", + DW_OP_neg: "", + DW_OP_not: "", + DW_OP_or: "", + DW_OP_plus: "", + DW_OP_plus_uconst: "u", + DW_OP_shl: "", + DW_OP_shr: "", + DW_OP_shra: "", + DW_OP_xor: "", + DW_OP_bra: "2", + DW_OP_eq: "", + DW_OP_ge: "", + DW_OP_gt: "", + DW_OP_le: "", + DW_OP_lt: "", + DW_OP_ne: "", + DW_OP_skip: "2", + DW_OP_lit0: "", + DW_OP_lit1: "", + DW_OP_lit2: "", + DW_OP_lit3: "", + DW_OP_lit4: "", + DW_OP_lit5: "", + DW_OP_lit6: "", + DW_OP_lit7: "", + DW_OP_lit8: "", + DW_OP_lit9: "", + DW_OP_lit10: "", + DW_OP_lit11: "", + DW_OP_lit12: "", + DW_OP_lit13: "", + DW_OP_lit14: "", + DW_OP_lit15: "", + DW_OP_lit16: "", + DW_OP_lit17: "", + DW_OP_lit18: "", + DW_OP_lit19: "", + DW_OP_lit20: "", + DW_OP_lit21: "", + DW_OP_lit22: "", + DW_OP_lit23: "", + DW_OP_lit24: "", + DW_OP_lit25: "", + DW_OP_lit26: "", + DW_OP_lit27: "", + DW_OP_lit28: "", + DW_OP_lit29: "", + DW_OP_lit30: "", + DW_OP_lit31: "", + DW_OP_reg0: "", + DW_OP_reg1: "", + DW_OP_reg2: "", + DW_OP_reg3: "", + DW_OP_reg4: "", + DW_OP_reg5: "", + DW_OP_reg6: "", + DW_OP_reg7: "", + DW_OP_reg8: "", + DW_OP_reg9: "", + DW_OP_reg10: "", + DW_OP_reg11: "", + DW_OP_reg12: "", + DW_OP_reg13: "", + DW_OP_reg14: "", + DW_OP_reg15: "", + DW_OP_reg16: "", + DW_OP_reg17: "", + DW_OP_reg18: "", + DW_OP_reg19: "", + DW_OP_reg20: "", + DW_OP_reg21: "", + DW_OP_reg22: "", + DW_OP_reg23: "", + DW_OP_reg24: "", + DW_OP_reg25: "", + DW_OP_reg26: "", + DW_OP_reg27: "", + DW_OP_reg28: "", + DW_OP_reg29: "", + DW_OP_reg30: "", + DW_OP_reg31: "", + DW_OP_breg0: "s", + DW_OP_breg1: "s", + DW_OP_breg2: "s", + DW_OP_breg3: "s", + DW_OP_breg4: "s", + DW_OP_breg5: "s", + DW_OP_breg6: "s", + DW_OP_breg7: "s", + DW_OP_breg8: "s", + DW_OP_breg9: "s", + DW_OP_breg10: "s", + DW_OP_breg11: "s", + DW_OP_breg12: "s", + DW_OP_breg13: "s", + DW_OP_breg14: "s", + DW_OP_breg15: "s", + DW_OP_breg16: "s", + DW_OP_breg17: "s", + DW_OP_breg18: "s", + DW_OP_breg19: "s", + DW_OP_breg20: "s", + DW_OP_breg21: "s", + DW_OP_breg22: "s", + DW_OP_breg23: "s", + DW_OP_breg24: "s", + DW_OP_breg25: "s", + DW_OP_breg26: "s", + DW_OP_breg27: "s", + DW_OP_breg28: "s", + DW_OP_breg29: "s", + DW_OP_breg30: "s", + DW_OP_breg31: "s", + DW_OP_regx: "s", + DW_OP_fbreg: "s", + DW_OP_bregx: "us", + DW_OP_piece: "u", + DW_OP_deref_size: "1", + DW_OP_xderef_size: "1", + DW_OP_nop: "", + DW_OP_push_object_address: "", + DW_OP_call2: "2", + DW_OP_call4: "4", + DW_OP_call_ref: "4", + DW_OP_form_tls_address: "", + DW_OP_call_frame_cfa: "", + DW_OP_bit_piece: "uu", + DW_OP_implicit_value: "B", + DW_OP_stack_value: "", +} +var oplut = map[Opcode]stackfn{ + DW_OP_addr: addr, + DW_OP_deref: deref, + DW_OP_const1u: constnu, + DW_OP_const1s: constns, + DW_OP_const2u: constnu, + DW_OP_const2s: constns, + DW_OP_const4u: constnu, + DW_OP_const4s: constns, + DW_OP_const8u: constnu, + DW_OP_const8s: constns, + DW_OP_constu: constu, + DW_OP_consts: consts, + DW_OP_dup: dup, + DW_OP_drop: drop, + DW_OP_over: pick, + DW_OP_pick: pick, + DW_OP_swap: swap, + DW_OP_rot: rot, + DW_OP_xderef: deref, + DW_OP_abs: unaryop, + DW_OP_and: binaryop, + DW_OP_div: binaryop, + DW_OP_minus: binaryop, + DW_OP_mod: binaryop, + DW_OP_mul: binaryop, + DW_OP_neg: unaryop, + DW_OP_not: unaryop, + DW_OP_or: binaryop, + DW_OP_plus: binaryop, + DW_OP_plus_uconst: plusuconsts, + DW_OP_shl: binaryop, + DW_OP_shr: binaryop, + DW_OP_shra: binaryop, + DW_OP_xor: binaryop, + DW_OP_bra: bra, + DW_OP_eq: binaryop, + DW_OP_ge: binaryop, + DW_OP_gt: binaryop, + DW_OP_le: binaryop, + DW_OP_lt: binaryop, + DW_OP_ne: binaryop, + DW_OP_skip: skip, + DW_OP_lit0: literal, + DW_OP_lit1: literal, + DW_OP_lit2: literal, + DW_OP_lit3: literal, + DW_OP_lit4: literal, + DW_OP_lit5: literal, + DW_OP_lit6: literal, + DW_OP_lit7: literal, + DW_OP_lit8: literal, + DW_OP_lit9: literal, + DW_OP_lit10: literal, + DW_OP_lit11: literal, + DW_OP_lit12: literal, + DW_OP_lit13: literal, + DW_OP_lit14: literal, + DW_OP_lit15: literal, + DW_OP_lit16: literal, + DW_OP_lit17: literal, + DW_OP_lit18: literal, + DW_OP_lit19: literal, + DW_OP_lit20: literal, + DW_OP_lit21: literal, + DW_OP_lit22: literal, + DW_OP_lit23: literal, + DW_OP_lit24: literal, + DW_OP_lit25: literal, + DW_OP_lit26: literal, + DW_OP_lit27: literal, + DW_OP_lit28: literal, + DW_OP_lit29: literal, + DW_OP_lit30: literal, + DW_OP_lit31: literal, + DW_OP_reg0: register, + DW_OP_reg1: register, + DW_OP_reg2: register, + DW_OP_reg3: register, + DW_OP_reg4: register, + DW_OP_reg5: register, + DW_OP_reg6: register, + DW_OP_reg7: register, + DW_OP_reg8: register, + DW_OP_reg9: register, + DW_OP_reg10: register, + DW_OP_reg11: register, + DW_OP_reg12: register, + DW_OP_reg13: register, + DW_OP_reg14: register, + DW_OP_reg15: register, + DW_OP_reg16: register, + DW_OP_reg17: register, + DW_OP_reg18: register, + DW_OP_reg19: register, + DW_OP_reg20: register, + DW_OP_reg21: register, + DW_OP_reg22: register, + DW_OP_reg23: register, + DW_OP_reg24: register, + DW_OP_reg25: register, + DW_OP_reg26: register, + DW_OP_reg27: register, + DW_OP_reg28: register, + DW_OP_reg29: register, + DW_OP_reg30: register, + DW_OP_reg31: register, + DW_OP_breg0: bregister, + DW_OP_breg1: bregister, + DW_OP_breg2: bregister, + DW_OP_breg3: bregister, + DW_OP_breg4: bregister, + DW_OP_breg5: bregister, + DW_OP_breg6: bregister, + DW_OP_breg7: bregister, + DW_OP_breg8: bregister, + DW_OP_breg9: bregister, + DW_OP_breg10: bregister, + DW_OP_breg11: bregister, + DW_OP_breg12: bregister, + DW_OP_breg13: bregister, + DW_OP_breg14: bregister, + DW_OP_breg15: bregister, + DW_OP_breg16: bregister, + DW_OP_breg17: bregister, + DW_OP_breg18: bregister, + DW_OP_breg19: bregister, + DW_OP_breg20: bregister, + DW_OP_breg21: bregister, + DW_OP_breg22: bregister, + DW_OP_breg23: bregister, + DW_OP_breg24: bregister, + DW_OP_breg25: bregister, + DW_OP_breg26: bregister, + DW_OP_breg27: bregister, + DW_OP_breg28: bregister, + DW_OP_breg29: bregister, + DW_OP_breg30: bregister, + DW_OP_breg31: bregister, + DW_OP_regx: register, + DW_OP_fbreg: framebase, + DW_OP_bregx: bregister, + DW_OP_piece: piece, + DW_OP_deref_size: deref, + DW_OP_xderef_size: deref, + DW_OP_call_frame_cfa: callframecfa, + DW_OP_implicit_value: implicitvalue, + DW_OP_stack_value: stackvalue, +}
diff --git a/third_party/delve/dwarf/op/opcodes.table b/third_party/delve/dwarf/op/opcodes.table new file mode 100644 index 0000000..e49e2c0 --- /dev/null +++ b/third_party/delve/dwarf/op/opcodes.table
@@ -0,0 +1,175 @@ +// This file is used by _scripts/gen-opcodes.go to generate +// pkg/dwarf/op/opcodes.go +// Lines starting with // are comments and will be discarded. +// Non empty lines contain the following tab separated fields: +// +// <opcode name> <opcode code> <arguments> <function name> +// +// With the last column, <function name>, being optional. +// +// The arguments field should contain a string with one character for each +// argument of the opcode: +// +// s signed variable length integer +// u unsigned variable length integer +// 1 one byte unsigned integer +// 2 two bytes unsigned integer +// 4 four bytes unsigned integer +// 8 eight bytes unsigned integer +// B an unsigned variable length integer 'n' followed by n a block of n bytes + + +DW_OP_addr 0x03 "8" addr +DW_OP_deref 0x06 "" deref +DW_OP_const1u 0x08 "1" constnu +DW_OP_const1s 0x09 "1" constns +DW_OP_const2u 0x0a "2" constnu +DW_OP_const2s 0x0b "2" constns +DW_OP_const4u 0x0c "4" constnu +DW_OP_const4s 0x0d "4" constns +DW_OP_const8u 0x0e "8" constnu +DW_OP_const8s 0x0f "8" constns +DW_OP_constu 0x10 "u" constu +DW_OP_consts 0x11 "s" consts +DW_OP_dup 0x12 "" dup +DW_OP_drop 0x13 "" drop +DW_OP_over 0x14 "" pick +DW_OP_pick 0x15 "" pick +DW_OP_swap 0x16 "" swap +DW_OP_rot 0x17 "" rot +DW_OP_xderef 0x18 "" deref +DW_OP_abs 0x19 "" unaryop +DW_OP_and 0x1a "" binaryop +DW_OP_div 0x1b "" binaryop +DW_OP_minus 0x1c "" binaryop +DW_OP_mod 0x1d "" binaryop +DW_OP_mul 0x1e "" binaryop +DW_OP_neg 0x1f "" unaryop +DW_OP_not 0x20 "" unaryop +DW_OP_or 0x21 "" binaryop +DW_OP_plus 0x22 "" binaryop +DW_OP_plus_uconst 0x23 "u" plusuconsts +DW_OP_shl 0x24 "" binaryop +DW_OP_shr 0x25 "" binaryop +DW_OP_shra 0x26 "" binaryop +DW_OP_xor 0x27 "" binaryop +DW_OP_bra 0x28 "2" bra +DW_OP_eq 0x29 "" binaryop +DW_OP_ge 0x2a "" binaryop +DW_OP_gt 0x2b "" binaryop +DW_OP_le 0x2c "" binaryop +DW_OP_lt 0x2d "" binaryop +DW_OP_ne 0x2e "" binaryop +DW_OP_skip 0x2f "2" skip +DW_OP_lit0 0x30 "" literal +DW_OP_lit1 0x31 "" literal +DW_OP_lit2 0x32 "" literal +DW_OP_lit3 0x33 "" literal +DW_OP_lit4 0x34 "" literal +DW_OP_lit5 0x35 "" literal +DW_OP_lit6 0x36 "" literal +DW_OP_lit7 0x37 "" literal +DW_OP_lit8 0x38 "" literal +DW_OP_lit9 0x39 "" literal +DW_OP_lit10 0x3a "" literal +DW_OP_lit11 0x3b "" literal +DW_OP_lit12 0x3c "" literal +DW_OP_lit13 0x3d "" literal +DW_OP_lit14 0x3e "" literal +DW_OP_lit15 0x3f "" literal +DW_OP_lit16 0x40 "" literal +DW_OP_lit17 0x41 "" literal +DW_OP_lit18 0x42 "" literal +DW_OP_lit19 0x43 "" literal +DW_OP_lit20 0x44 "" literal +DW_OP_lit21 0x45 "" literal +DW_OP_lit22 0x46 "" literal +DW_OP_lit23 0x47 "" literal +DW_OP_lit24 0x48 "" literal +DW_OP_lit25 0x49 "" literal +DW_OP_lit26 0x4a "" literal +DW_OP_lit27 0x4b "" literal +DW_OP_lit28 0x4c "" literal +DW_OP_lit29 0x4d "" literal +DW_OP_lit30 0x4e "" literal +DW_OP_lit31 0x4f "" literal +DW_OP_reg0 0x50 "" register +DW_OP_reg1 0x51 "" register +DW_OP_reg2 0x52 "" register +DW_OP_reg3 0x53 "" register +DW_OP_reg4 0x54 "" register +DW_OP_reg5 0x55 "" register +DW_OP_reg6 0x56 "" register +DW_OP_reg7 0x57 "" register +DW_OP_reg8 0x58 "" register +DW_OP_reg9 0x59 "" register +DW_OP_reg10 0x5a "" register +DW_OP_reg11 0x5b "" register +DW_OP_reg12 0x5c "" register +DW_OP_reg13 0x5d "" register +DW_OP_reg14 0x5e "" register +DW_OP_reg15 0x5f "" register +DW_OP_reg16 0x60 "" register +DW_OP_reg17 0x61 "" register +DW_OP_reg18 0x62 "" register +DW_OP_reg19 0x63 "" register +DW_OP_reg20 0x64 "" register +DW_OP_reg21 0x65 "" register +DW_OP_reg22 0x66 "" register +DW_OP_reg23 0x67 "" register +DW_OP_reg24 0x68 "" register +DW_OP_reg25 0x69 "" register +DW_OP_reg26 0x6a "" register +DW_OP_reg27 0x6b "" register +DW_OP_reg28 0x6c "" register +DW_OP_reg29 0x6d "" register +DW_OP_reg30 0x6e "" register +DW_OP_reg31 0x6f "" register +DW_OP_breg0 0x70 "s" bregister +DW_OP_breg1 0x71 "s" bregister +DW_OP_breg2 0x72 "s" bregister +DW_OP_breg3 0x73 "s" bregister +DW_OP_breg4 0x74 "s" bregister +DW_OP_breg5 0x75 "s" bregister +DW_OP_breg6 0x76 "s" bregister +DW_OP_breg7 0x77 "s" bregister +DW_OP_breg8 0x78 "s" bregister +DW_OP_breg9 0x79 "s" bregister +DW_OP_breg10 0x7a "s" bregister +DW_OP_breg11 0x7b "s" bregister +DW_OP_breg12 0x7c "s" bregister +DW_OP_breg13 0x7d "s" bregister +DW_OP_breg14 0x7e "s" bregister +DW_OP_breg15 0x7f "s" bregister +DW_OP_breg16 0x80 "s" bregister +DW_OP_breg17 0x81 "s" bregister +DW_OP_breg18 0x82 "s" bregister +DW_OP_breg19 0x83 "s" bregister +DW_OP_breg20 0x84 "s" bregister +DW_OP_breg21 0x85 "s" bregister +DW_OP_breg22 0x86 "s" bregister +DW_OP_breg23 0x87 "s" bregister +DW_OP_breg24 0x88 "s" bregister +DW_OP_breg25 0x89 "s" bregister +DW_OP_breg26 0x8a "s" bregister +DW_OP_breg27 0x8b "s" bregister +DW_OP_breg28 0x8c "s" bregister +DW_OP_breg29 0x8d "s" bregister +DW_OP_breg30 0x8e "s" bregister +DW_OP_breg31 0x8f "s" bregister +DW_OP_regx 0x90 "s" register +DW_OP_fbreg 0x91 "s" framebase +DW_OP_bregx 0x92 "us" bregister +DW_OP_piece 0x93 "u" piece +DW_OP_deref_size 0x94 "1" deref +DW_OP_xderef_size 0x95 "1" deref +DW_OP_nop 0x96 "" +DW_OP_push_object_address 0x97 "" +DW_OP_call2 0x98 "2" +DW_OP_call4 0x99 "4" +DW_OP_call_ref 0x9a "4" +DW_OP_form_tls_address 0x9b "" +DW_OP_call_frame_cfa 0x9c "" callframecfa +DW_OP_bit_piece 0x9d "uu" +DW_OP_implicit_value 0x9e "B" implicitvalue +DW_OP_stack_value 0x9f "" stackvalue
diff --git a/third_party/delve/dwarf/op/regs.go b/third_party/delve/dwarf/op/regs.go new file mode 100644 index 0000000..bd95e79 --- /dev/null +++ b/third_party/delve/dwarf/op/regs.go
@@ -0,0 +1,183 @@ +package op + +import ( + "bytes" + "encoding/binary" +) + +// DwarfRegisters holds the value of stack program registers. +type DwarfRegisters struct { + StaticBase uint64 + + CFA int64 + FrameBase int64 + ObjBase int64 + regs []*DwarfRegister + + ByteOrder binary.ByteOrder + PCRegNum uint64 + SPRegNum uint64 + BPRegNum uint64 + LRRegNum uint64 + ChangeFunc RegisterChangeFunc + + FloatLoadError error // error produced when loading floating point registers + loadMoreCallback func() +} + +type DwarfRegister struct { + Uint64Val uint64 + Bytes []byte +} + +type RegisterChangeFunc func(regNum uint64, reg *DwarfRegister) error + +// NewDwarfRegisters returns a new DwarfRegisters object. +func NewDwarfRegisters(staticBase uint64, regs []*DwarfRegister, byteOrder binary.ByteOrder, pcRegNum, spRegNum, bpRegNum, lrRegNum uint64) *DwarfRegisters { + return &DwarfRegisters{ + StaticBase: staticBase, + regs: regs, + ByteOrder: byteOrder, + PCRegNum: pcRegNum, + SPRegNum: spRegNum, + BPRegNum: bpRegNum, + LRRegNum: lrRegNum, + } +} + +// SetLoadMoreCallback sets a callback function that will be called the +// first time the user of regs tries to access an undefined register. +func (regs *DwarfRegisters) SetLoadMoreCallback(fn func()) { + regs.loadMoreCallback = fn +} + +// CurrentSize returns the current number of known registers. This number might be +// wrong if loadMoreCallback has been set. +func (regs *DwarfRegisters) CurrentSize() int { + return len(regs.regs) +} + +// Uint64Val returns the uint64 value of register idx. +func (regs *DwarfRegisters) Uint64Val(idx uint64) uint64 { + reg := regs.Reg(idx) + if reg == nil { + return 0 + } + return regs.regs[idx].Uint64Val +} + +// Bytes returns the bytes value of register idx, nil if the register is not +// defined. +func (regs *DwarfRegisters) Bytes(idx uint64) []byte { + reg := regs.Reg(idx) + if reg == nil { + return nil + } + if reg.Bytes == nil { + var buf bytes.Buffer + binary.Write(&buf, regs.ByteOrder, reg.Uint64Val) + reg.Bytes = buf.Bytes() + } + return reg.Bytes +} + +func (regs *DwarfRegisters) loadMore() { + if regs.loadMoreCallback == nil { + return + } + regs.loadMoreCallback() + regs.loadMoreCallback = nil +} + +// Reg returns register idx or nil if the register is not defined. +func (regs *DwarfRegisters) Reg(idx uint64) *DwarfRegister { + if idx >= uint64(len(regs.regs)) { + regs.loadMore() + if idx >= uint64(len(regs.regs)) { + return nil + } + } + if regs.regs[idx] == nil { + regs.loadMore() + } + return regs.regs[idx] +} + +func (regs *DwarfRegisters) PC() uint64 { + return regs.Uint64Val(regs.PCRegNum) +} + +func (regs *DwarfRegisters) SP() uint64 { + return regs.Uint64Val(regs.SPRegNum) +} + +func (regs *DwarfRegisters) BP() uint64 { + return regs.Uint64Val(regs.BPRegNum) +} + +// AddReg adds register idx to regs. +func (regs *DwarfRegisters) AddReg(idx uint64, reg *DwarfRegister) { + if idx >= uint64(len(regs.regs)) { + newRegs := make([]*DwarfRegister, idx+1) + copy(newRegs, regs.regs) + regs.regs = newRegs + } + regs.regs[idx] = reg +} + +// ClearRegisters clears all registers. +func (regs *DwarfRegisters) ClearRegisters() { + regs.loadMoreCallback = nil + for regnum := range regs.regs { + regs.regs[regnum] = nil + } +} + +func DwarfRegisterFromUint64(v uint64) *DwarfRegister { + return &DwarfRegister{Uint64Val: v} +} + +func DwarfRegisterFromBytes(bytes []byte) *DwarfRegister { + var v uint64 + switch len(bytes) { + case 1: + v = uint64(bytes[0]) + case 2: + x := binary.LittleEndian.Uint16(bytes) + v = uint64(x) + case 4: + x := binary.LittleEndian.Uint32(bytes) + v = uint64(x) + default: + if len(bytes) >= 8 { + v = binary.LittleEndian.Uint64(bytes[:8]) + } + } + return &DwarfRegister{Uint64Val: v, Bytes: bytes} +} + +// FillBytes fills the Bytes slice of reg using Uint64Val. +func (reg *DwarfRegister) FillBytes() { + if reg.Bytes != nil { + return + } + reg.Bytes = make([]byte, 8) + binary.LittleEndian.PutUint64(reg.Bytes, reg.Uint64Val) +} + +// Overwrite takes the contents of reg and overwrites them with the contents +// of reg2 in little-endian order, returning a new register. The new register +// will always contain the complete contents of both registers, so if reg2 is +// larger than reg, the final register will be reg2's size. +func (reg *DwarfRegister) Overwrite(reg2 *DwarfRegister) *DwarfRegister { + reg.FillBytes() + reg2.FillBytes() + width := len(reg.Bytes) + if len(reg2.Bytes) > len(reg.Bytes) { + width = len(reg2.Bytes) + } + b := make([]byte, width) + copy(b, reg.Bytes) + copy(b, reg2.Bytes) + return DwarfRegisterFromBytes(b) +}
diff --git a/third_party/delve/dwarf/parseutil.go b/third_party/delve/dwarf/parseutil.go new file mode 100644 index 0000000..d8ed2b0 --- /dev/null +++ b/third_party/delve/dwarf/parseutil.go
@@ -0,0 +1,150 @@ +package dwarf + +import ( + "bytes" + "debug/dwarf" + "encoding/binary" + "fmt" + "io" +) + +// ReadString reads a null-terminated string from data. +func ReadString(data *bytes.Buffer) (string, error) { + str, err := data.ReadString(0x0) + if err != nil { + return "", err + } + + return str[:len(str)-1], nil +} + +// 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 2: + var n uint16 + if err := binary.Read(reader, order, &n); err != nil { + return 0, err + } + return uint64(n), nil + 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("pointer size %d not supported", 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("pointer size %d not supported", ptrSize) +} + +// ReadDwarfLengthVersion 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 +}
diff --git a/third_party/delve/dwarf/regnum/amd64.go b/third_party/delve/dwarf/regnum/amd64.go new file mode 100644 index 0000000..2fcbb4e --- /dev/null +++ b/third_party/delve/dwarf/regnum/amd64.go
@@ -0,0 +1,162 @@ +package regnum + +import ( + "fmt" + "strings" +) + +// The mapping between hardware registers and DWARF registers is specified +// in the System V ABI AMD64 Architecture Processor Supplement v. 1.0 page 61, +// figure 3.36 +// https://gitlab.com/x86-psABIs/x86-64-ABI/-/tree/master + +const ( + AMD64_Rax = 0 + AMD64_Rdx = 1 + AMD64_Rcx = 2 + AMD64_Rbx = 3 + AMD64_Rsi = 4 + AMD64_Rdi = 5 + AMD64_Rbp = 6 + AMD64_Rsp = 7 + AMD64_R8 = 8 + AMD64_R9 = 9 + AMD64_R10 = 10 + AMD64_R11 = 11 + AMD64_R12 = 12 + AMD64_R13 = 13 + AMD64_R14 = 14 + AMD64_R15 = 15 + AMD64_Rip = 16 + AMD64_XMM0 = 17 // XMM1 through XMM15 follow + AMD64_ST0 = 33 // ST(1) through ST(7) follow + AMD64_Rflags = 49 + AMD64_Es = 50 + AMD64_Cs = 51 + AMD64_Ss = 52 + AMD64_Ds = 53 + AMD64_Fs = 54 + AMD64_Gs = 55 + AMD64_Fs_base = 58 + AMD64_Gs_base = 59 + AMD64_MXCSR = 64 + AMD64_CW = 65 + AMD64_SW = 66 + AMD64_XMM16 = 67 // XMM17 through XMM31 follow + AMD64_K0 = 118 // k1 through k7 follow +) + +var amd64DwarfToName = map[uint64]string{ + AMD64_Rax: "Rax", + AMD64_Rdx: "Rdx", + AMD64_Rcx: "Rcx", + AMD64_Rbx: "Rbx", + AMD64_Rsi: "Rsi", + AMD64_Rdi: "Rdi", + AMD64_Rbp: "Rbp", + AMD64_Rsp: "Rsp", + AMD64_R8: "R8", + AMD64_R9: "R9", + AMD64_R10: "R10", + AMD64_R11: "R11", + AMD64_R12: "R12", + AMD64_R13: "R13", + AMD64_R14: "R14", + AMD64_R15: "R15", + AMD64_Rip: "Rip", + AMD64_XMM0: "XMM0", + AMD64_XMM0 + 1: "XMM1", + AMD64_XMM0 + 2: "XMM2", + AMD64_XMM0 + 3: "XMM3", + AMD64_XMM0 + 4: "XMM4", + AMD64_XMM0 + 5: "XMM5", + AMD64_XMM0 + 6: "XMM6", + AMD64_XMM0 + 7: "XMM7", + AMD64_XMM0 + 8: "XMM8", + AMD64_XMM0 + 9: "XMM9", + AMD64_XMM0 + 10: "XMM10", + AMD64_XMM0 + 11: "XMM11", + AMD64_XMM0 + 12: "XMM12", + AMD64_XMM0 + 13: "XMM13", + AMD64_XMM0 + 14: "XMM14", + AMD64_XMM0 + 15: "XMM15", + AMD64_ST0: "ST(0)", + AMD64_ST0 + 1: "ST(1)", + AMD64_ST0 + 2: "ST(2)", + AMD64_ST0 + 3: "ST(3)", + AMD64_ST0 + 4: "ST(4)", + AMD64_ST0 + 5: "ST(5)", + AMD64_ST0 + 6: "ST(6)", + AMD64_ST0 + 7: "ST(7)", + AMD64_Rflags: "Rflags", + AMD64_Es: "Es", + AMD64_Cs: "Cs", + AMD64_Ss: "Ss", + AMD64_Ds: "Ds", + AMD64_Fs: "Fs", + AMD64_Gs: "Gs", + AMD64_Fs_base: "Fs_base", + AMD64_Gs_base: "Gs_base", + AMD64_MXCSR: "MXCSR", + AMD64_CW: "CW", + AMD64_SW: "SW", + AMD64_XMM16: "XMM16", + AMD64_XMM16 + 1: "XMM17", + AMD64_XMM16 + 2: "XMM18", + AMD64_XMM16 + 3: "XMM19", + AMD64_XMM16 + 4: "XMM20", + AMD64_XMM16 + 5: "XMM21", + AMD64_XMM16 + 6: "XMM22", + AMD64_XMM16 + 7: "XMM23", + AMD64_XMM16 + 8: "XMM24", + AMD64_XMM16 + 9: "XMM25", + AMD64_XMM16 + 10: "XMM26", + AMD64_XMM16 + 11: "XMM27", + AMD64_XMM16 + 12: "XMM28", + AMD64_XMM16 + 13: "XMM29", + AMD64_XMM16 + 14: "XMM30", + AMD64_XMM16 + 15: "XMM31", + AMD64_K0: "K0", + AMD64_K0 + 1: "K1", + AMD64_K0 + 2: "K2", + AMD64_K0 + 3: "K3", + AMD64_K0 + 4: "K4", + AMD64_K0 + 5: "K5", + AMD64_K0 + 6: "K6", + AMD64_K0 + 7: "K7", +} + +var AMD64NameToDwarf = func() map[string]int { + r := make(map[string]int) + for regNum, regName := range amd64DwarfToName { + r[strings.ToLower(regName)] = int(regNum) + } + r["eflags"] = 49 + r["st0"] = 33 + r["st1"] = 34 + r["st2"] = 35 + r["st3"] = 36 + r["st4"] = 37 + r["st5"] = 38 + r["st6"] = 39 + r["st7"] = 40 + return r +}() + +func AMD64MaxRegNum() uint64 { + max := uint64(AMD64_Rip) + for i := range amd64DwarfToName { + if i > max { + max = i + } + } + return max +} + +func AMD64ToName(num uint64) string { + name, ok := amd64DwarfToName[num] + if ok { + return name + } + return fmt.Sprintf("unknown%d", num) +}
diff --git a/third_party/delve/dwarf/regnum/arm64.go b/third_party/delve/dwarf/regnum/arm64.go new file mode 100644 index 0000000..80aff3f --- /dev/null +++ b/third_party/delve/dwarf/regnum/arm64.go
@@ -0,0 +1,56 @@ +package regnum + +import ( + "fmt" +) + +// The mapping between hardware registers and DWARF registers is specified +// in the DWARF for the DWARF for the Arm® 64-bit Architecture (AArch64), +// Section 4, Table 1 +// https://github.com/ARM-software/abi-aa/blob/main/aadwarf64/aadwarf64.rst#4arm-specific-dwarf-definitions + +const ( + ARM64_X0 = 0 // X1 through X30 follow + ARM64_BP = 29 // also X29 + ARM64_LR = 30 // also X30 + ARM64_SP = 31 + ARM64_PC = 32 + ARM64_V0 = 64 // V1 through V31 follow + _ARM64_MaxRegNum = ARM64_V0 + 31 +) + +func ARM64ToName(num uint64) string { + switch { + case num <= 30: + return fmt.Sprintf("X%d", num) + case num == ARM64_SP: + return "SP" + case num == ARM64_PC: + return "PC" + case num >= ARM64_V0 && num <= 95: + return fmt.Sprintf("V%d", num-64) + default: + return fmt.Sprintf("unknown%d", num) + } +} + +func ARM64MaxRegNum() uint64 { + return _ARM64_MaxRegNum +} + +var ARM64NameToDwarf = func() map[string]int { + r := make(map[string]int) + for i := 0; i <= 32; i++ { + r[fmt.Sprintf("x%d", i)] = ARM64_X0 + i + } + r["fp"] = 29 + r["lr"] = 30 + r["sp"] = 31 + r["pc"] = 32 + + for i := 0; i <= 31; i++ { + r[fmt.Sprintf("v%d", i)] = ARM64_V0 + i + } + + return r +}()
diff --git a/third_party/delve/dwarf/regnum/i386.go b/third_party/delve/dwarf/regnum/i386.go new file mode 100644 index 0000000..a671b46 --- /dev/null +++ b/third_party/delve/dwarf/regnum/i386.go
@@ -0,0 +1,102 @@ +package regnum + +import ( + "fmt" + "strings" +) + +// The mapping between hardware registers and DWARF registers is specified +// in the System V ABI Intel386 Architecture Processor Supplement page 25, +// table 2.14 +// https://www.uclibc.org/docs/psABI-i386.pdf + +const ( + I386_Eax = 0 + I386_Ecx = 1 + I386_Edx = 2 + I386_Ebx = 3 + I386_Esp = 4 + I386_Ebp = 5 + I386_Esi = 6 + I386_Edi = 7 + I386_Eip = 8 + I386_Eflags = 9 + I386_ST0 = 11 // ST(1) through ST(7) follow + I386_XMM0 = 21 // XMM1 through XMM7 follow + I386_Es = 40 + I386_Cs = 41 + I386_Ss = 42 + I386_Ds = 43 + I386_Fs = 44 + I386_Gs = 45 +) + +var i386DwarfToName = map[int]string{ + I386_Eax: "Eax", + I386_Ecx: "Ecx", + I386_Edx: "Edx", + I386_Ebx: "Ebx", + I386_Esp: "Esp", + I386_Ebp: "Ebp", + I386_Esi: "Esi", + I386_Edi: "Edi", + I386_Eip: "Eip", + I386_Eflags: "Eflags", + I386_ST0: "ST(0)", + I386_ST0 + 1: "ST(1)", + I386_ST0 + 2: "ST(2)", + I386_ST0 + 3: "ST(3)", + I386_ST0 + 4: "ST(4)", + I386_ST0 + 5: "ST(5)", + I386_ST0 + 6: "ST(6)", + I386_ST0 + 7: "ST(7)", + I386_XMM0: "XMM0", + I386_XMM0 + 1: "XMM1", + I386_XMM0 + 2: "XMM2", + I386_XMM0 + 3: "XMM3", + I386_XMM0 + 4: "XMM4", + I386_XMM0 + 5: "XMM5", + I386_XMM0 + 6: "XMM6", + I386_XMM0 + 7: "XMM7", + I386_Es: "Es", + I386_Cs: "Cs", + I386_Ss: "Ss", + I386_Ds: "Ds", + I386_Fs: "Fs", + I386_Gs: "Gs", +} + +var I386NameToDwarf = func() map[string]int { + r := make(map[string]int) + for regNum, regName := range i386DwarfToName { + r[strings.ToLower(regName)] = regNum + } + r["eflags"] = 9 + r["st0"] = 11 + r["st1"] = 12 + r["st2"] = 13 + r["st3"] = 14 + r["st4"] = 15 + r["st5"] = 16 + r["st6"] = 17 + r["st7"] = 18 + return r +}() + +func I386MaxRegNum() int { + max := int(I386_Eip) + for i := range i386DwarfToName { + if i > max { + max = i + } + } + return max +} + +func I386ToName(num uint64) string { + name, ok := i386DwarfToName[int(num)] + if ok { + return name + } + return fmt.Sprintf("unknown%d", num) +}
diff --git a/third_party/delve/dwarf/regnum/ppc64le.go b/third_party/delve/dwarf/regnum/ppc64le.go new file mode 100644 index 0000000..4a0291b --- /dev/null +++ b/third_party/delve/dwarf/regnum/ppc64le.go
@@ -0,0 +1,116 @@ +package regnum + +import "fmt" + +// The mapping between hardware registers and DWARF registers is specified +// in the 64-Bit ELF V2 ABI Specification of the Power Architecture in section +// 2.4 DWARF Definition +// https://openpowerfoundation.org/specifications/64bitelfabi/ + +const ( + // General Purpose Registers: from R0 to R31 + PPC64LE_FIRST_GPR = 0 + PPC64LE_R0 = PPC64LE_FIRST_GPR + PPC64LE_LAST_GPR = 31 + // Floating point registers: from F0 to F31 + PPC64LE_FIRST_FPR = 32 + PPC64LE_F0 = PPC64LE_FIRST_FPR + PPC64LE_LAST_FPR = 63 + // Vector (Altivec/VMX) registers: from V0 to V31 + PPC64LE_FIRST_VMX = 77 + PPC64LE_V0 = PPC64LE_FIRST_VMX + PPC64LE_LAST_VMX = 108 + // Vector Scalar (VSX) registers: from VS32 to VS63 + // On ppc64le these are mapped to F0 to F31 + PPC64LE_FIRST_VSX = 32 + PPC64LE_VS0 = PPC64LE_FIRST_VSX + PPC64LE_LAST_VSX = 63 + // Condition Registers: from CR0 to CR7 + PPC64LE_CR0 = 0 + // Special registers + PPC64LE_SP = 1 // Stack frame pointer: Gpr[1] + PPC64LE_PC = 12 // The documentation refers to this as the CIA (Current Instruction Address) + PPC64LE_LR = 65 // Link register +) + +func PPC64LEToName(num uint64) string { + switch { + case num == PPC64LE_SP: + return "SP" + case num == PPC64LE_PC: + return "PC" + case num == PPC64LE_LR: + return "LR" + case isGPR(num): + return fmt.Sprintf("r%d", int(num-PPC64LE_FIRST_GPR)) + case isFPR(num): + return fmt.Sprintf("f%d", int(num-PPC64LE_FIRST_FPR)) + case isVMX(num): + return fmt.Sprintf("v%d", int(num-PPC64LE_FIRST_VMX)) + case isVSX(num): + return fmt.Sprintf("vs%d", int(num-PPC64LE_FIRST_VSX)) + default: + return fmt.Sprintf("unknown%d", num) + } +} + +// PPC64LEMaxRegNum is 172 registers in total, across 4 categories: +// General Purpose Registers or GPR (32 GPR + 9 special registers) +// Floating Point Registers or FPR (32 FPR + 1 special register) +// Altivec/VMX Registers or VMX (32 VMX + 2 special registers) +// VSX Registers or VSX (64 VSX) +// Documentation: https://lldb.llvm.org/cpp_reference/RegisterContextPOSIX__ppc64le_8cpp_source.html +func PPC64LEMaxRegNum() uint64 { + return 172 +} + +func isGPR(num uint64) bool { + return num < PPC64LE_LAST_GPR +} + +func isFPR(num uint64) bool { + return num >= PPC64LE_FIRST_FPR && num <= PPC64LE_LAST_FPR +} + +func isVMX(num uint64) bool { + return num >= PPC64LE_FIRST_VMX && num <= PPC64LE_LAST_VMX +} + +func isVSX(num uint64) bool { + return num >= PPC64LE_FIRST_VSX && num <= PPC64LE_LAST_VSX +} + +var PPC64LENameToDwarf = func() map[string]int { + r := make(map[string]int) + + r["nip"] = PPC64LE_PC + r["sp"] = PPC64LE_SP + r["bp"] = PPC64LE_SP + r["link"] = PPC64LE_LR + + // General Purpose Registers: from R0 to R31 + for i := 0; i <= 31; i++ { + r[fmt.Sprintf("r%d", i)] = PPC64LE_R0 + i + } + + // Floating point registers: from F0 to F31 + for i := 0; i <= 31; i++ { + r[fmt.Sprintf("f%d", i)] = PPC64LE_F0 + i + } + + // Vector (Altivec/VMX) registers: from V0 to V31 + for i := 0; i <= 31; i++ { + r[fmt.Sprintf("v%d", i)] = PPC64LE_V0 + i + } + + // Vector Scalar (VSX) registers: from VS0 to VS63 + for i := 0; i <= 63; i++ { + r[fmt.Sprintf("vs%d", i)] = PPC64LE_VS0 + i + } + + // Condition Registers: from CR0 to CR7 + for i := 0; i <= 7; i++ { + r[fmt.Sprintf("cr%d", i)] = PPC64LE_CR0 + i + } + return r +}()
diff --git a/third_party/delve/dwarf/regnum/riscv64.go b/third_party/delve/dwarf/regnum/riscv64.go new file mode 100644 index 0000000..08a2723 --- /dev/null +++ b/third_party/delve/dwarf/regnum/riscv64.go
@@ -0,0 +1,92 @@ +package regnum + +import "fmt" + +// The mapping between hardware registers and DWARF registers, See +// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-dwarf.adoc + +const ( + // Integer Registers + RISCV64_X0 = 0 + // Link Register + RISCV64_LR = 1 + // Stack Pointer + RISCV64_SP = 2 + RISCV64_GP = 3 + RISCV64_TP = 4 + RISCV64_T0 = 5 + RISCV64_T1 = 6 + RISCV64_T2 = 7 + RISCV64_S0 = 8 + // Frame Pointer + RISCV64_FP = RISCV64_S0 + RISCV64_S1 = 9 + RISCV64_A0 = 10 + RISCV64_A1 = 11 + RISCV64_A2 = 12 + RISCV64_A3 = 13 + RISCV64_A4 = 14 + RISCV64_A5 = 15 + RISCV64_A6 = 16 + RISCV64_A7 = 17 + RISCV64_S2 = 18 + RISCV64_S3 = 19 + RISCV64_S4 = 20 + RISCV64_S5 = 21 + RISCV64_S6 = 22 + RISCV64_S7 = 23 + RISCV64_S8 = 24 + RISCV64_S9 = 25 + RISCV64_S10 = 26 + // G Register + RISCV64_S11 = 27 + RISCV64_T3 = 28 + RISCV64_T4 = 29 + RISCV64_T5 = 30 + RISCV64_T6 = 31 + + RISCV64_X31 = RISCV64_T6 + + // Floating-point Registers + RISCV64_F0 = 32 + RISCV64_F31 = 63 + + // Not defined in DWARF specification + RISCV64_PC = 65 + + _RISC64_MaxRegNum = RISCV64_PC +) + +func RISCV64ToName(num uint64) string { + switch { + case num <= RISCV64_X31: + return fmt.Sprintf("X%d", num) + + case num >= RISCV64_F0 && num <= RISCV64_F31: + return fmt.Sprintf("F%d", num) + + case num == RISCV64_PC: + return "PC" + + default: + return fmt.Sprintf("Unknown%d", num) + } +} + +func RISCV64MaxRegNum() uint64 { + return _RISC64_MaxRegNum +} + +var RISCV64NameToDwarf = func() map[string]int { + r := make(map[string]int) + for i := 0; i <= 31; i++ { + r[fmt.Sprintf("x%d", i)] = RISCV64_X0 + i + } + r["pc"] = RISCV64_PC + + for i := 0; i <= 31; i++ { + r[fmt.Sprintf("f%d", i)] = RISCV64_F0 + i + } + + return r +}()