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
+}()