Skip to content

Commit

Permalink
proc: replace debug/dwarf with golang.org/x/debug/dwarf
Browse files Browse the repository at this point in the history
Typedefs that resolve to slices are not recorded in DWARF as typedefs
but instead as structs in a way that there is no way to know they
are really slices using debug/dwarf.
Using golang.org/x/debug/dwarf instead this problem is solved and
as a bonus some types are printed with a nicer names: (struct string
→ string, struct []int → []int, etc)

 Fixes go-delve#356 and go-delve#293
  • Loading branch information
aarzilli authored and Derek Parker committed Jan 24, 2016
1 parent b164023 commit 54f1c9b
Show file tree
Hide file tree
Showing 41 changed files with 6,761 additions and 2,357 deletions.
18 changes: 13 additions & 5 deletions Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 14 additions & 1 deletion _fixtures/testvariables3.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ type benchstruct struct {
b [64]byte
}

type Item struct {
Name string
Route string
Active int
}

type Menu []Item

func main() {
i1 := 1
i2 := 2
Expand Down Expand Up @@ -145,6 +153,11 @@ func main() {
mapinf["inf"] = mapinf
var bencharr [64]benchstruct
var benchparr [64]*benchstruct
mainMenu := Menu{
{Name: "home", Route: "/", Active: 1},
{Name: "About", Route: "/about", Active: 1},
{Name: "Login", Route: "/login", Active: 1},
}

for i := range benchparr {
benchparr[i] = &benchstruct{}
Expand All @@ -156,5 +169,5 @@ func main() {
fmt.Println(amb1)
}
runtime.Breakpoint()
fmt.Println(i1, i2, i3, p1, amb1, s1, s3, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf)
fmt.Println(i1, i2, i3, p1, amb1, s1, s3, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu)
}
2 changes: 1 addition & 1 deletion dwarf/reader/reader.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package reader

import (
"debug/dwarf"
"errors"
"fmt"
"golang.org/x/debug/dwarf"

"github.com/derekparker/delve/dwarf/op"
)
Expand Down
29 changes: 13 additions & 16 deletions proc/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package proc

import (
"bytes"
"debug/dwarf"
"encoding/binary"
"fmt"
"go/ast"
"go/constant"
"go/parser"
"go/printer"
"go/token"
"golang.org/x/debug/dwarf"
"reflect"

"github.com/derekparker/delve/dwarf/reader"
Expand Down Expand Up @@ -142,9 +142,6 @@ func (scope *EvalScope) evalTypeCast(node *ast.CallExpr) (*Variable, error) {

switch ttyp := typ.(type) {
case *dwarf.PtrType:
if ptrTypeKind(ttyp) != reflect.Ptr {
return nil, converr
}
switch argv.Kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
// ok
Expand Down Expand Up @@ -1002,7 +999,7 @@ func (v *Variable) isType(typ dwarf.Type, kind reflect.Kind) error {
return converr
}

switch t := typ.(type) {
switch typ.(type) {
case *dwarf.IntType:
if v.Value.Kind() != constant.Int {
return converr
Expand All @@ -1019,10 +1016,7 @@ func (v *Variable) isType(typ dwarf.Type, kind reflect.Kind) error {
if v.Value.Kind() != constant.Bool {
return converr
}
case *dwarf.StructType:
if t.StructName != "string" {
return converr
}
case *dwarf.StringType:
if v.Value.Kind() != constant.String {
return converr
}
Expand Down Expand Up @@ -1092,14 +1086,17 @@ func (v *Variable) reslice(low int64, high int64) (*Variable, error) {

typ := v.DwarfType
if _, isarr := v.DwarfType.(*dwarf.ArrayType); isarr {
typ = &dwarf.StructType{
CommonType: dwarf.CommonType{
ByteSize: 24,
Name: "",
typ = &dwarf.SliceType{
StructType: dwarf.StructType{
CommonType: dwarf.CommonType{
ByteSize: 24,
Name: "",
},
StructName: fmt.Sprintf("[]%s", v.fieldType),
Kind: "struct",
Field: nil,
},
StructName: fmt.Sprintf("[]%s", v.fieldType),
Kind: "struct",
Field: nil,
ElemType: v.fieldType,
}
}

Expand Down
2 changes: 1 addition & 1 deletion proc/proc.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package proc

import (
"debug/dwarf"
"debug/gosym"
"encoding/binary"
"errors"
"fmt"
"go/ast"
"go/constant"
"go/token"
"golang.org/x/debug/dwarf"
"os"
"path/filepath"
"runtime"
Expand Down
5 changes: 2 additions & 3 deletions proc/proc_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ package proc
import "C"
import (
"debug/gosym"
"debug/macho"
"errors"
"fmt"
"golang.org/x/debug/macho"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -273,11 +273,10 @@ func (dbp *Process) findExecutable(path string) (*macho.File, error) {
if err != nil {
return nil, err
}
data, err := exe.DWARF()
dbp.dwarf, err = exe.DWARF()
if err != nil {
return nil, err
}
dbp.dwarf = data
return exe, nil
}

Expand Down
5 changes: 2 additions & 3 deletions proc/proc_linux.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package proc

import (
"debug/elf"
"debug/gosym"
"errors"
"fmt"
"golang.org/x/debug/elf"
"io/ioutil"
"os"
"os/exec"
Expand Down Expand Up @@ -168,11 +168,10 @@ func (dbp *Process) findExecutable(path string) (*elf.File, error) {
if err != nil {
return nil, err
}
data, err := elfFile.DWARF()
dbp.dwarf, err = elfFile.DWARF()
if err != nil {
return nil, err
}
dbp.dwarf = data
return elfFile, nil
}

Expand Down
12 changes: 12 additions & 0 deletions proc/proc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1426,3 +1426,15 @@ func TestCondBreakpointError(t *testing.T) {
}
})
}

func TestIssue356(t *testing.T) {
// slice with a typedef does not get printed correctly
withTestProcess("testvariables3", t, func(p *Process, fixture protest.Fixture) {
assertNoError(p.Continue(), t, "Continue() returned an error")
mmvar, err := evalVariable(p, "mainMenu")
assertNoError(err, t, "EvalVariable()")
if mmvar.Kind != reflect.Slice {
t.Fatalf("Wrong kind for mainMenu: %v\n", mmvar.Kind)
}
})
}
32 changes: 30 additions & 2 deletions proc/proc_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
"syscall"
"unsafe"

"golang.org/x/debug/dwarf"

sys "golang.org/x/sys/windows"

"github.com/derekparker/delve/dwarf/frame"
Expand Down Expand Up @@ -304,14 +306,40 @@ func (dbp *Process) findExecutable(path string) (*pe.File, error) {
if err != nil {
return nil, err
}
data, err := peFile.DWARF()
dbp.dwarf, err = dwarfFromPE(peFile)
if err != nil {
return nil, err
}
dbp.dwarf = data
return peFile, nil
}

// Adapted from src/debug/pe/file.go: pe.(*File).DWARF()
func dwarfFromPE(f *pe.File) (*dwarf.Data, error) {
// There are many other DWARF sections, but these
// are the ones the debug/dwarf package uses.
// Don't bother loading others.
var names = [...]string{"abbrev", "info", "line", "str"}
var dat [len(names)][]byte
for i, name := range names {
name = ".debug_" + name
s := f.Section(name)
if s == nil {
continue
}
b, err := s.Data()
if err != nil && uint32(len(b)) < s.Size {
return nil, err
}
if 0 < s.VirtualSize && s.VirtualSize < s.Size {
b = b[:s.VirtualSize]
}
dat[i] = b
}

abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3]
return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
}

func (dbp *Process) waitForDebugEvent() (threadID, exitCode int, err error) {
var debugEvent C.DEBUG_EVENT
for {
Expand Down
5 changes: 3 additions & 2 deletions proc/threads.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package proc

import (
"debug/dwarf"
"debug/gosym"
"encoding/binary"
"fmt"
"golang.org/x/debug/dwarf"
"path/filepath"
"reflect"
"runtime"

"github.com/derekparker/delve/dwarf/frame"
Expand Down Expand Up @@ -284,7 +285,7 @@ func (thread *Thread) newGVariable(gaddr uintptr, deref bool) (*Variable, error)
name := ""

if deref {
typ = &dwarf.PtrType{dwarf.CommonType{int64(thread.dbp.arch.PtrSize()), ""}, typ}
typ = &dwarf.PtrType{dwarf.CommonType{int64(thread.dbp.arch.PtrSize()), "", reflect.Ptr, 0}, typ}
} else {
name = "runtime.curg"
}
Expand Down
5 changes: 3 additions & 2 deletions proc/types.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package proc

import (
"debug/dwarf"
"go/ast"
"golang.org/x/debug/dwarf"
"reflect"
"strings"
)

Expand All @@ -17,7 +18,7 @@ func (dbp *Process) findType(name string) (dwarf.Type, error) {
}

func (dbp *Process) pointerTo(typ dwarf.Type) dwarf.Type {
return &dwarf.PtrType{dwarf.CommonType{int64(dbp.arch.PtrSize()), ""}, typ}
return &dwarf.PtrType{dwarf.CommonType{int64(dbp.arch.PtrSize()), "", reflect.Ptr, 0}, typ}
}

func (dbp *Process) findTypeExpr(expr ast.Expr) (dwarf.Type, error) {
Expand Down
Loading

0 comments on commit 54f1c9b

Please sign in to comment.