conversions.go 4.7 KB
Newer Older
1 2
package api

A
aarzilli 已提交
3
import (
4
	"bytes"
A
aarzilli 已提交
5
	"debug/gosym"
6
	"go/constant"
7 8
	"go/printer"
	"go/token"
9
	"golang.org/x/debug/dwarf"
10
	"reflect"
11
	"strconv"
D
Derek Parker 已提交
12

A
aarzilli 已提交
13 14
	"github.com/derekparker/delve/proc"
)
15

D
Derek Parker 已提交
16 17
// ConvertBreakpoint converts from a proc.Breakpoint to
// an api.Breakpoint.
18
func ConvertBreakpoint(bp *proc.Breakpoint) *Breakpoint {
19
	b := &Breakpoint{
20
		Name:          bp.Name,
21 22 23 24 25 26 27 28 29 30
		ID:            bp.ID,
		FunctionName:  bp.FunctionName,
		File:          bp.File,
		Line:          bp.Line,
		Addr:          bp.Addr,
		Tracepoint:    bp.Tracepoint,
		Stacktrace:    bp.Stacktrace,
		Goroutine:     bp.Goroutine,
		Variables:     bp.Variables,
		TotalHitCount: bp.TotalHitCount,
31
	}
32 33 34 35 36 37

	b.HitCount = map[string]uint64{}
	for idx := range bp.HitCount {
		b.HitCount[strconv.Itoa(idx)] = bp.HitCount[idx]
	}

38 39 40 41
	var buf bytes.Buffer
	printer.Fprint(&buf, token.NewFileSet(), bp.Cond)
	b.Cond = buf.String()

42
	return b
43 44
}

D
Derek Parker 已提交
45 46
// ConvertThread converts a proc.Thread into an
// api thread.
47 48 49 50 51 52
func ConvertThread(th *proc.Thread) *Thread {
	var (
		function *Function
		file     string
		line     int
		pc       uint64
53
		gid      int
54 55 56 57 58 59 60
	)

	loc, err := th.Location()
	if err == nil {
		pc = loc.PC
		file = loc.File
		line = loc.Line
A
aarzilli 已提交
61
		function = ConvertFunction(loc.Fn)
62 63
	}

64 65
	var bp *Breakpoint

66
	if th.CurrentBreakpoint != nil && th.BreakpointConditionMet {
67 68 69 70
		bp = ConvertBreakpoint(th.CurrentBreakpoint)
	}

	if g, _ := th.GetG(); g != nil {
D
Derek Parker 已提交
71
		gid = g.ID
72 73
	}

74
	return &Thread{
D
Derek Parker 已提交
75
		ID:          th.ID,
76 77 78 79 80 81
		PC:          pc,
		File:        file,
		Line:        line,
		Function:    function,
		GoroutineID: gid,
		Breakpoint:  bp,
82 83 84
	}
}

85 86 87 88 89 90 91 92 93 94 95
func prettyTypeName(typ dwarf.Type) string {
	if typ == nil {
		return ""
	}
	r := typ.String()
	if r == "*void" {
		return "unsafe.Pointer"
	}
	return r
}

D
Derek Parker 已提交
96
// ConvertVar converts from proc.Variable to api.Variable.
97 98
func ConvertVar(v *proc.Variable) *Variable {
	r := Variable{
A
aarzilli 已提交
99 100 101 102 103 104
		Addr:     v.Addr,
		OnlyAddr: v.OnlyAddr,
		Name:     v.Name,
		Kind:     v.Kind,
		Len:      v.Len,
		Cap:      v.Cap,
105
	}
106

107 108
	r.Type = prettyTypeName(v.DwarfType)
	r.RealType = prettyTypeName(v.RealType)
109 110 111 112 113

	if v.Unreadable != nil {
		r.Unreadable = v.Unreadable.Error()
	}

114 115 116 117 118 119 120 121 122 123 124 125
	if v.Value != nil {
		switch v.Kind {
		case reflect.Float32:
			f, _ := constant.Float64Val(v.Value)
			r.Value = strconv.FormatFloat(f, 'f', -1, 32)
		case reflect.Float64:
			f, _ := constant.Float64Val(v.Value)
			r.Value = strconv.FormatFloat(f, 'f', -1, 64)
		case reflect.String, reflect.Func:
			r.Value = constant.StringVal(v.Value)
		default:
			r.Value = v.Value.String()
126 127 128
		}
	}

A
aarzilli 已提交
129 130 131 132
	switch v.Kind {
	case reflect.Complex64:
		r.Children = make([]Variable, 2)
		r.Len = 2
133

A
aarzilli 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
		real, _ := constant.Float64Val(constant.Real(v.Value))
		imag, _ := constant.Float64Val(constant.Imag(v.Value))

		r.Children[0].Name = "real"
		r.Children[0].Kind = reflect.Float32
		r.Children[0].Value = strconv.FormatFloat(real, 'f', -1, 32)

		r.Children[1].Name = "imaginary"
		r.Children[1].Kind = reflect.Float32
		r.Children[1].Value = strconv.FormatFloat(imag, 'f', -1, 32)
	case reflect.Complex128:
		r.Children = make([]Variable, 2)
		r.Len = 2

		real, _ := constant.Float64Val(constant.Real(v.Value))
		imag, _ := constant.Float64Val(constant.Imag(v.Value))

		r.Children[0].Name = "real"
		r.Children[0].Kind = reflect.Float64
		r.Children[0].Value = strconv.FormatFloat(real, 'f', -1, 64)

		r.Children[1].Name = "imaginary"
		r.Children[1].Kind = reflect.Float64
		r.Children[1].Value = strconv.FormatFloat(imag, 'f', -1, 64)

	default:
		r.Children = make([]Variable, len(v.Children))

		for i := range v.Children {
			r.Children[i] = *ConvertVar(&v.Children[i])
		}
165 166 167
	}

	return &r
168 169
}

D
Derek Parker 已提交
170 171
// ConvertFunction converts from gosym.Func to
// api.Function.
A
aarzilli 已提交
172 173 174 175 176 177 178 179 180 181
func ConvertFunction(fn *gosym.Func) *Function {
	if fn == nil {
		return nil
	}

	return &Function{
		Name:   fn.Name,
		Type:   fn.Type,
		Value:  fn.Value,
		GoType: fn.GoType,
182
	}
A
aarzilli 已提交
183
}
184

D
Derek Parker 已提交
185
// ConvertGoroutine converts from proc.G to api.Goroutine.
A
aarzilli 已提交
186
func ConvertGoroutine(g *proc.G) *Goroutine {
187
	return &Goroutine{
D
Derek Parker 已提交
188
		ID:             g.ID,
189 190 191
		CurrentLoc:     ConvertLocation(g.CurrentLoc),
		UserCurrentLoc: ConvertLocation(g.UserCurrent()),
		GoStatementLoc: ConvertLocation(g.Go()),
A
aarzilli 已提交
192 193 194
	}
}

D
Derek Parker 已提交
195
// ConvertLocation converts from proc.Location to api.Location.
A
aarzilli 已提交
196 197 198
func ConvertLocation(loc proc.Location) Location {
	return Location{
		PC:       loc.PC,
199
		File:     loc.File,
A
aarzilli 已提交
200 201
		Line:     loc.Line,
		Function: ConvertFunction(loc.Fn),
202 203
	}
}
A
aarzilli 已提交
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219

func ConvertAsmInstruction(inst proc.AsmInstruction, text string) AsmInstruction {
	var destloc *Location
	if inst.DestLoc != nil {
		r := ConvertLocation(*inst.DestLoc)
		destloc = &r
	}
	return AsmInstruction{
		Loc:        ConvertLocation(inst.Loc),
		DestLoc:    destloc,
		Text:       text,
		Bytes:      inst.Bytes,
		Breakpoint: inst.Breakpoint,
		AtPC:       inst.AtPC,
	}
}