Skip to content

Commit

Permalink
proc: some refactorings for supporting struct literals
Browse files Browse the repository at this point in the history
* deduplicates exprToString, defined in multiple packages, and moves it
  to astutil
* moves resolveTypedef into pkg/dwarf/godwarf, this is currently only
  used by pkg/proc but we will need to call it from pkg/proc/evalop
* creates a new FakePointerType function in pkg/dwarf/godwarf, this is
  also a function that is only used by pkg/proc but pkg/proc/evalop will
  also need.

Updates #1465
  • Loading branch information
aarzilli committed Jan 22, 2025
1 parent d2f748f commit 7a3cc07
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 87 deletions.
8 changes: 8 additions & 0 deletions pkg/astutil/astutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package astutil

import (
"bytes"
"go/ast"
"go/printer"
"go/token"
"strconv"
)
Expand Down Expand Up @@ -43,3 +45,9 @@ func Or(x, y ast.Expr) ast.Expr {
}
return &ast.BinaryExpr{Op: token.LOR, X: x, Y: y}
}

func ExprToString(t ast.Expr) string {
var buf bytes.Buffer
printer.Fprint(&buf, token.NewFileSet(), t)
return buf.String()
}
6 changes: 6 additions & 0 deletions pkg/dwarf/godwarf/fakes.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,9 @@ func FakeBasicType(name string, bitSize int) Type {
panic("unsupported")
}
}

// FakePointerType synthesizes a pointer type
func FakePointerType(typ Type, ptrSize int64) *PtrType {
typename := "*" + typ.Common().Name
return &PtrType{CommonType: CommonType{ByteSize: ptrSize, Name: typename}, Type: typ}
}
13 changes: 13 additions & 0 deletions pkg/dwarf/godwarf/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -1101,3 +1101,16 @@ func zeroArray(t Type) {
t = at.Type
}
}

func ResolveTypedef(typ Type) Type {
for {
switch tt := typ.(type) {
case *TypedefType:
typ = tt.Type
case *QualType:
typ = tt.Type
default:
return typ
}
}
}
5 changes: 3 additions & 2 deletions pkg/proc/bininfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"sync"
"time"

"github.com/go-delve/delve/pkg/astutil"
pdwarf "github.com/go-delve/delve/pkg/dwarf"
"github.com/go-delve/delve/pkg/dwarf/frame"
"github.com/go-delve/delve/pkg/dwarf/godwarf"
Expand Down Expand Up @@ -2374,10 +2375,10 @@ func (bi *BinaryInfo) findTypeExpr(expr ast.Expr) (godwarf.Type, error) {
alen, litlen := anode.Len.(*ast.BasicLit)
if litlen && alen.Kind == token.INT {
n, _ := strconv.Atoi(alen.Value)
return bi.findArrayType(n, exprToString(anode.Elt))
return bi.findArrayType(n, astutil.ExprToString(anode.Elt))
}
}
return bi.findType(exprToString(expr))
return bi.findType(astutil.ExprToString(expr))
}

func (bi *BinaryInfo) findArrayType(n int, etyp string) (godwarf.Type, error) {
Expand Down
15 changes: 8 additions & 7 deletions pkg/proc/breakpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"go/token"
"reflect"

"github.com/go-delve/delve/pkg/astutil"
"github.com/go-delve/delve/pkg/dwarf/godwarf"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/reader"
Expand Down Expand Up @@ -213,25 +214,25 @@ func (bp *Breakpoint) VerboseDescr() []string {
for _, breaklet := range bp.Breaklets {
switch breaklet.Kind {
case UserBreakpoint:
r = append(r, fmt.Sprintf("User Cond=%q HitCond=%v", exprToString(breaklet.Cond), lbp.hitCond))
r = append(r, fmt.Sprintf("User Cond=%q HitCond=%v", astutil.ExprToString(breaklet.Cond), lbp.HitCond()))
case NextBreakpoint:
r = append(r, fmt.Sprintf("Next Cond=%q", exprToString(breaklet.Cond)))
r = append(r, fmt.Sprintf("Next Cond=%q", astutil.ExprToString(breaklet.Cond)))
case NextDeferBreakpoint:
r = append(r, fmt.Sprintf("NextDefer Cond=%q DeferReturns=%#x", exprToString(breaklet.Cond), breaklet.DeferReturns))
r = append(r, fmt.Sprintf("NextDefer Cond=%q DeferReturns=%#x", astutil.ExprToString(breaklet.Cond), breaklet.DeferReturns))
case StepBreakpoint:
r = append(r, fmt.Sprintf("Step Cond=%q", exprToString(breaklet.Cond)))
r = append(r, fmt.Sprintf("Step Cond=%q", astutil.ExprToString(breaklet.Cond)))
case WatchOutOfScopeBreakpoint:
r = append(r, fmt.Sprintf("WatchOutOfScope Cond=%q checkPanicCall=%v", exprToString(breaklet.Cond), breaklet.checkPanicCall))
r = append(r, fmt.Sprintf("WatchOutOfScope Cond=%q checkPanicCall=%v", astutil.ExprToString(breaklet.Cond), breaklet.checkPanicCall))
case StackResizeBreakpoint:
r = append(r, fmt.Sprintf("StackResizeBreakpoint Cond=%q", exprToString(breaklet.Cond)))
r = append(r, fmt.Sprintf("StackResizeBreakpoint Cond=%q", astutil.ExprToString(breaklet.Cond)))
case PluginOpenBreakpoint:
r = append(r, "PluginOpenBreakpoint")
case StepIntoNewProcBreakpoint:
r = append(r, "StepIntoNewProcBreakpoint")
case NextInactivatedBreakpoint:
r = append(r, "NextInactivatedBreakpoint")
case StepIntoRangeOverFuncBodyBreakpoint:
r = append(r, "StepIntoRangeOverFuncBodyBreakpoint Cond=%q", exprToString(breaklet.Cond))
r = append(r, "StepIntoRangeOverFuncBodyBreakpoint Cond=%q", astutil.ExprToString(breaklet.Cond))
default:
r = append(r, fmt.Sprintf("Unknown %d", breaklet.Kind))
}
Expand Down
64 changes: 28 additions & 36 deletions pkg/proc/eval.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package proc

import (
"bytes"
"debug/dwarf"
"errors"
"fmt"
"go/ast"
"go/constant"
"go/parser"
"go/printer"
"go/token"
"reflect"
"runtime/debug"
"sort"
"strings"

"github.com/go-delve/delve/pkg/astutil"
"github.com/go-delve/delve/pkg/dwarf/godwarf"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/reader"
Expand Down Expand Up @@ -1181,7 +1180,7 @@ func (stack *evalStack) executeOp() {
fncall := stack.fncallPeek()
actualArg := stack.pop()
if actualArg.Name == "" {
actualArg.Name = exprToString(op.ArgExpr)
actualArg.Name = astutil.ExprToString(op.ArgExpr)
}
stack.err = funcCallCopyOneArg(scope, fncall, actualArg, &fncall.formalArgs[op.ArgNum], curthread)

Expand Down Expand Up @@ -1218,7 +1217,7 @@ func (stack *evalStack) executeOp() {
case *evalop.SetValue:
lhv := stack.pop()
rhv := stack.pop()
stack.err = scope.setValue(lhv, rhv, exprToString(op.Rhe))
stack.err = scope.setValue(lhv, rhv, astutil.ExprToString(op.Rhe))

case *evalop.PushPinAddress:
debugPinCount++
Expand Down Expand Up @@ -1349,12 +1348,6 @@ func (scope *EvalScope) evalAST(t ast.Expr) (*Variable, error) {
return stack.result(nil)
}

func exprToString(t ast.Expr) string {
var buf bytes.Buffer
printer.Fprint(&buf, token.NewFileSet(), t)
return buf.String()
}

func (scope *EvalScope) evalJump(op *evalop.Jump, stack *evalStack) {
var x *Variable

Expand Down Expand Up @@ -1395,7 +1388,7 @@ func (scope *EvalScope) evalJump(op *evalop.Jump, stack *evalStack) {

if x.Kind != reflect.Bool {
if op.Node != nil {
stack.err = fmt.Errorf("expression %q should be boolean not %s", exprToString(op.Node), x.Kind)
stack.err = fmt.Errorf("expression %q should be boolean not %s", astutil.ExprToString(op.Node), x.Kind)
} else {
stack.err = errors.New("internal debugger error: expected boolean")
}
Expand All @@ -1415,9 +1408,9 @@ func (scope *EvalScope) evalJump(op *evalop.Jump, stack *evalStack) {
func (scope *EvalScope) evalTypeCast(op *evalop.TypeCast, stack *evalStack) {
argv := stack.pop()

typ := resolveTypedef(op.DwarfType)
typ := godwarf.ResolveTypedef(op.DwarfType)

converr := fmt.Errorf("can not convert %q to %s", exprToString(op.Node.Args[0]), typ.String())
converr := fmt.Errorf("can not convert %q to %s", astutil.ExprToString(op.Node.Args[0]), typ.String())

// compatible underlying types
if typeCastCompatibleTypes(argv.RealType, typ) {
Expand Down Expand Up @@ -1708,7 +1701,7 @@ func typeCastCompatibleTypes(typ1, typ2 godwarf.Type) bool {
return true
}
// pointer types are compatible if their element types are compatible
return typeCastCompatibleTypes(resolveTypedef(ttyp1.Type), resolveTypedef(ttyp2.Type))
return typeCastCompatibleTypes(godwarf.ResolveTypedef(ttyp1.Type), godwarf.ResolveTypedef(ttyp2.Type))
}
case *godwarf.StringType:
if _, ok := typ2.(*godwarf.StringType); ok {
Expand Down Expand Up @@ -1784,7 +1777,7 @@ func capBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
}

arg := args[0]
invalidArgErr := fmt.Errorf("invalid argument %s (type %s) for cap", exprToString(nodeargs[0]), arg.TypeString())
invalidArgErr := fmt.Errorf("invalid argument %s (type %s) for cap", astutil.ExprToString(nodeargs[0]), arg.TypeString())

switch arg.Kind {
case reflect.Ptr:
Expand Down Expand Up @@ -1816,7 +1809,7 @@ func lenBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
return nil, fmt.Errorf("wrong number of arguments to len: %d", len(args))
}
arg := args[0]
invalidArgErr := fmt.Errorf("invalid argument %s (type %s) for len", exprToString(nodeargs[0]), arg.TypeString())
invalidArgErr := fmt.Errorf("invalid argument %s (type %s) for len", astutil.ExprToString(nodeargs[0]), arg.TypeString())

switch arg.Kind {
case reflect.Ptr:
Expand Down Expand Up @@ -1873,11 +1866,11 @@ func complexBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
}

if realev.Value == nil || ((realev.Value.Kind() != constant.Int) && (realev.Value.Kind() != constant.Float)) {
return nil, fmt.Errorf("invalid argument 1 %s (type %s) to complex", exprToString(nodeargs[0]), realev.TypeString())
return nil, fmt.Errorf("invalid argument 1 %s (type %s) to complex", astutil.ExprToString(nodeargs[0]), realev.TypeString())
}

if imagev.Value == nil || ((imagev.Value.Kind() != constant.Int) && (imagev.Value.Kind() != constant.Float)) {
return nil, fmt.Errorf("invalid argument 2 %s (type %s) to complex", exprToString(nodeargs[1]), imagev.TypeString())
return nil, fmt.Errorf("invalid argument 2 %s (type %s) to complex", astutil.ExprToString(nodeargs[1]), imagev.TypeString())
}

sz := int64(0)
Expand Down Expand Up @@ -1915,7 +1908,7 @@ func imagBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
}

if arg.Kind != reflect.Complex64 && arg.Kind != reflect.Complex128 {
return nil, fmt.Errorf("invalid argument %s (type %s) to imag", exprToString(nodeargs[0]), arg.TypeString())
return nil, fmt.Errorf("invalid argument %s (type %s) to imag", astutil.ExprToString(nodeargs[0]), arg.TypeString())
}

return newConstant(constant.Imag(arg.Value), arg.mem), nil
Expand All @@ -1934,7 +1927,7 @@ func realBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
}

if arg.Value == nil || ((arg.Value.Kind() != constant.Int) && (arg.Value.Kind() != constant.Float) && (arg.Value.Kind() != constant.Complex)) {
return nil, fmt.Errorf("invalid argument %s (type %s) to real", exprToString(nodeargs[0]), arg.TypeString())
return nil, fmt.Errorf("invalid argument %s (type %s) to real", astutil.ExprToString(nodeargs[0]), arg.TypeString())
}

return newConstant(constant.Real(arg.Value), arg.mem), nil
Expand All @@ -1959,7 +1952,7 @@ func minmaxBuiltin(name string, op token.Token, args []*Variable, nodeargs []ast
}

if args[i].Unreadable != nil {
return nil, fmt.Errorf("could not load %q: %v", exprToString(nodeargs[i]), args[i].Unreadable)
return nil, fmt.Errorf("could not load %q: %v", astutil.ExprToString(nodeargs[i]), args[i].Unreadable)
}
if args[i].FloatSpecial != 0 {
return nil, errOperationOnSpecialFloat
Expand Down Expand Up @@ -2026,7 +2019,7 @@ func (scope *EvalScope) evalStructSelector(op *evalop.Select, stack *evalStack)
func (scope *EvalScope) evalTypeAssert(op *evalop.TypeAssert, stack *evalStack) {
xv := stack.pop()
if xv.Kind != reflect.Interface {
stack.err = fmt.Errorf("expression %q not an interface", exprToString(op.Node.X))
stack.err = fmt.Errorf("expression %q not an interface", astutil.ExprToString(op.Node.X))
return
}
xv.loadInterface(0, false, loadFullValue)
Expand All @@ -2039,7 +2032,7 @@ func (scope *EvalScope) evalTypeAssert(op *evalop.TypeAssert, stack *evalStack)
return
}
if xv.Children[0].Addr == 0 {
stack.err = fmt.Errorf("interface conversion: %s is nil, not %s", xv.DwarfType.String(), exprToString(op.Node.Type))
stack.err = fmt.Errorf("interface conversion: %s is nil, not %s", xv.DwarfType.String(), astutil.ExprToString(op.Node.Type))
return
}
typ := op.DwarfType
Expand Down Expand Up @@ -2068,7 +2061,7 @@ func (scope *EvalScope) evalIndex(op *evalop.Index, stack *evalStack) {
xev = xev.maybeDereference()
}

cantindex := fmt.Errorf("expression %q (%s) does not support indexing", exprToString(op.Node.X), xev.TypeString())
cantindex := fmt.Errorf("expression %q (%s) does not support indexing", astutil.ExprToString(op.Node.X), xev.TypeString())

switch xev.Kind {
case reflect.Ptr:
Expand All @@ -2088,7 +2081,7 @@ func (scope *EvalScope) evalIndex(op *evalop.Index, stack *evalStack) {

case reflect.Slice, reflect.Array, reflect.String:
if xev.Base == 0 {
stack.err = fmt.Errorf("can not index %q", exprToString(op.Node.X))
stack.err = fmt.Errorf("can not index %q", astutil.ExprToString(op.Node.X))
return
}
n, err := idxev.asInt()
Expand Down Expand Up @@ -2141,7 +2134,7 @@ func (scope *EvalScope) evalReslice(op *evalop.Reslice, stack *evalStack) {
switch xev.Kind {
case reflect.Slice, reflect.Array, reflect.String:
if xev.Base == 0 {
stack.err = fmt.Errorf("can not slice %q", exprToString(op.Node.X))
stack.err = fmt.Errorf("can not slice %q", astutil.ExprToString(op.Node.X))
return
}
stack.pushErr(xev.reslice(low, high, op.TrustLen))
Expand All @@ -2166,7 +2159,7 @@ func (scope *EvalScope) evalReslice(op *evalop.Reslice, stack *evalStack) {
}
fallthrough
default:
stack.err = fmt.Errorf("can not slice %q (type %s)", exprToString(op.Node.X), xev.TypeString())
stack.err = fmt.Errorf("can not slice %q (type %s)", astutil.ExprToString(op.Node.X), xev.TypeString())
return
}
}
Expand All @@ -2176,7 +2169,7 @@ func (scope *EvalScope) evalPointerDeref(op *evalop.PointerDeref, stack *evalSta
xev := stack.pop()

if xev.Kind != reflect.Ptr {
stack.err = fmt.Errorf("expression %q (%s) can not be dereferenced", exprToString(op.Node.X), xev.TypeString())
stack.err = fmt.Errorf("expression %q (%s) can not be dereferenced", astutil.ExprToString(op.Node.X), xev.TypeString())
return
}

Expand Down Expand Up @@ -2211,7 +2204,7 @@ func (scope *EvalScope) evalPointerDeref(op *evalop.PointerDeref, stack *evalSta
func (scope *EvalScope) evalAddrOf(op *evalop.AddrOf, stack *evalStack) {
xev := stack.pop()
if xev.Addr == 0 || xev.DwarfType == nil {
stack.err = fmt.Errorf("can not take address of %q", exprToString(op.Node.X))
stack.err = fmt.Errorf("can not take address of %q", astutil.ExprToString(op.Node.X))
return
}

Expand All @@ -2221,8 +2214,7 @@ func (scope *EvalScope) evalAddrOf(op *evalop.AddrOf, stack *evalStack) {
func (v *Variable) pointerToVariable() *Variable {
v.OnlyAddr = true

typename := "*" + v.DwarfType.Common().Name
rv := v.newVariable("", 0, &godwarf.PtrType{CommonType: godwarf.CommonType{ByteSize: int64(v.bi.Arch.PtrSize()), Name: typename}, Type: v.DwarfType}, v.mem)
rv := v.newVariable("", 0, godwarf.FakePointerType(v.DwarfType, int64(v.bi.Arch.PtrSize())), v.mem)
rv.Children = []Variable{*v}
rv.loaded = true

Expand Down Expand Up @@ -2279,7 +2271,7 @@ func (scope *EvalScope) evalUnary(op *evalop.Unary, stack *evalStack) {
return
}
if xv.Value == nil {
stack.err = fmt.Errorf("operator %s can not be applied to %q", op.Node.Op.String(), exprToString(op.Node.X))
stack.err = fmt.Errorf("operator %s can not be applied to %q", op.Node.Op.String(), astutil.ExprToString(op.Node.X))
return
}
rc, err := constantUnaryOp(op.Node.Op, xv.Value)
Expand Down Expand Up @@ -2434,12 +2426,12 @@ func (scope *EvalScope) evalBinary(binop *evalop.Binary, stack *evalStack) {
yv.loadValue(loadFullValueLongerStrings)
}
if xv.Value == nil {
stack.err = fmt.Errorf("operator %s can not be applied to %q", node.Op.String(), exprToString(node.X))
stack.err = fmt.Errorf("operator %s can not be applied to %q", node.Op.String(), astutil.ExprToString(node.X))
return
}

if yv.Value == nil {
stack.err = fmt.Errorf("operator %s can not be applied to %q", node.Op.String(), exprToString(node.Y))
stack.err = fmt.Errorf("operator %s can not be applied to %q", node.Op.String(), astutil.ExprToString(node.Y))
return
}

Expand Down Expand Up @@ -2700,8 +2692,8 @@ func sameType(t1, t2 godwarf.Type) bool {
// consistent, however we also synthesize some types ourselves
// (specifically pointers and slices) and we always use a reference through
// a typedef.
t1 = resolveTypedef(t1)
t2 = resolveTypedef(t2)
t1 = godwarf.ResolveTypedef(t1)
t2 = godwarf.ResolveTypedef(t2)

if tt1, isptr1 := t1.(*godwarf.PtrType); isptr1 {
tt2, isptr2 := t2.(*godwarf.PtrType)
Expand Down
Loading

0 comments on commit 7a3cc07

Please sign in to comment.