conversions.go 6.3 KB
Newer Older
1 2
package api

A
aarzilli 已提交
3
import (
4
	"bytes"
5
	"go/constant"
6 7
	"go/printer"
	"go/token"
8
	"reflect"
9
	"strconv"
D
Derek Parker 已提交
10

11
	"github.com/derekparker/delve/pkg/dwarf/godwarf"
D
Derek Parker 已提交
12
	"github.com/derekparker/delve/pkg/proc"
A
aarzilli 已提交
13
)
14

D
Derek Parker 已提交
15 16
// ConvertBreakpoint converts from a proc.Breakpoint to
// an api.Breakpoint.
17
func ConvertBreakpoint(bp *proc.Breakpoint) *Breakpoint {
18
	b := &Breakpoint{
19
		Name:          bp.Name,
20 21 22 23 24 25 26 27 28
		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,
29 30
		LoadArgs:      LoadConfigFromProc(bp.LoadArgs),
		LoadLocals:    LoadConfigFromProc(bp.LoadLocals),
31
		TotalHitCount: bp.TotalHitCount,
32
	}
33 34 35 36 37 38

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

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

43
	return b
44 45
}

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

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

65 66
	var bp *Breakpoint

67 68
	if b := th.Breakpoint(); b.Active {
		bp = ConvertBreakpoint(b.Breakpoint)
69 70
	}

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

75
	return &Thread{
76
		ID:          th.ThreadID(),
77 78 79 80 81 82
		PC:          pc,
		File:        file,
		Line:        line,
		Function:    function,
		GoroutineID: gid,
		Breakpoint:  bp,
83 84 85
	}
}

86
func prettyTypeName(typ godwarf.Type) string {
87 88 89
	if typ == nil {
		return ""
	}
90 91 92
	if typ.Common().Name != "" {
		return typ.Common().Name
	}
93 94 95 96 97 98 99
	r := typ.String()
	if r == "*void" {
		return "unsafe.Pointer"
	}
	return r
}

100 101 102 103 104 105 106 107 108 109 110 111 112
func convertFloatValue(v *proc.Variable, sz int) string {
	switch v.FloatSpecial {
	case proc.FloatIsPosInf:
		return "+Inf"
	case proc.FloatIsNegInf:
		return "-Inf"
	case proc.FloatIsNaN:
		return "NaN"
	}
	f, _ := constant.Float64Val(v.Value)
	return strconv.FormatFloat(f, 'f', -1, sz)
}

D
Derek Parker 已提交
113
// ConvertVar converts from proc.Variable to api.Variable.
114 115
func ConvertVar(v *proc.Variable) *Variable {
	r := Variable{
A
aarzilli 已提交
116 117 118 119 120 121
		Addr:     v.Addr,
		OnlyAddr: v.OnlyAddr,
		Name:     v.Name,
		Kind:     v.Kind,
		Len:      v.Len,
		Cap:      v.Cap,
122
		Flags:    VariableFlags(v.Flags),
123
		Base:     v.Base,
124
	}
125

126 127
	r.Type = prettyTypeName(v.DwarfType)
	r.RealType = prettyTypeName(v.RealType)
128 129 130 131 132

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

133 134 135
	if v.Value != nil {
		switch v.Kind {
		case reflect.Float32:
136
			r.Value = convertFloatValue(v, 32)
137
		case reflect.Float64:
138
			r.Value = convertFloatValue(v, 64)
139 140 141 142
		case reflect.String, reflect.Func:
			r.Value = constant.StringVal(v.Value)
		default:
			r.Value = v.Value.String()
143 144 145
		}
	}

A
aarzilli 已提交
146 147 148 149
	switch v.Kind {
	case reflect.Complex64:
		r.Children = make([]Variable, 2)
		r.Len = 2
150

A
aarzilli 已提交
151 152 153 154 155
		r.Children[0].Name = "real"
		r.Children[0].Kind = reflect.Float32

		r.Children[1].Name = "imaginary"
		r.Children[1].Kind = reflect.Float32
156 157 158 159 160 161 162 163 164 165 166 167

		if v.Value != nil {
			real, _ := constant.Float64Val(constant.Real(v.Value))
			r.Children[0].Value = strconv.FormatFloat(real, 'f', -1, 32)

			imag, _ := constant.Float64Val(constant.Imag(v.Value))
			r.Children[1].Value = strconv.FormatFloat(imag, 'f', -1, 32)
		} else {
			r.Children[0].Value = "nil"
			r.Children[1].Value = "nil"
		}

A
aarzilli 已提交
168 169 170 171 172 173 174 175 176
	case reflect.Complex128:
		r.Children = make([]Variable, 2)
		r.Len = 2

		r.Children[0].Name = "real"
		r.Children[0].Kind = reflect.Float64

		r.Children[1].Name = "imaginary"
		r.Children[1].Kind = reflect.Float64
177 178 179 180 181 182 183 184 185 186 187

		if v.Value != nil {
			real, _ := constant.Float64Val(constant.Real(v.Value))
			r.Children[0].Value = strconv.FormatFloat(real, 'f', -1, 64)

			imag, _ := constant.Float64Val(constant.Imag(v.Value))
			r.Children[1].Value = strconv.FormatFloat(imag, 'f', -1, 64)
		} else {
			r.Children[0].Value = "nil"
			r.Children[1].Value = "nil"
		}
A
aarzilli 已提交
188 189 190 191 192 193 194

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

		for i := range v.Children {
			r.Children[i] = *ConvertVar(&v.Children[i])
		}
195 196 197
	}

	return &r
198 199
}

D
Derek Parker 已提交
200 201
// ConvertFunction converts from gosym.Func to
// api.Function.
202
func ConvertFunction(fn *proc.Function) *Function {
A
aarzilli 已提交
203 204 205 206
	if fn == nil {
		return nil
	}

207 208 209 210
	// fn here used to be a *gosym.Func, the fields Type and GoType below
	// corresponded to the omonymous field of gosym.Func. Since the contents of
	// those fields is not documented their value was replaced with 0 when
	// gosym.Func was replaced by debug_info entries.
A
aarzilli 已提交
211 212
	return &Function{
		Name:   fn.Name,
213 214 215
		Type:   0,
		Value:  fn.Entry,
		GoType: 0,
216
	}
A
aarzilli 已提交
217
}
218

D
Derek Parker 已提交
219
// ConvertGoroutine converts from proc.G to api.Goroutine.
A
aarzilli 已提交
220
func ConvertGoroutine(g *proc.G) *Goroutine {
221
	th := g.Thread
222 223
	tid := 0
	if th != nil {
224
		tid = th.ThreadID()
225
	}
226
	return &Goroutine{
D
Derek Parker 已提交
227
		ID:             g.ID,
228 229 230
		CurrentLoc:     ConvertLocation(g.CurrentLoc),
		UserCurrentLoc: ConvertLocation(g.UserCurrent()),
		GoStatementLoc: ConvertLocation(g.Go()),
A
aarzilli 已提交
231
		ThreadID:       tid,
A
aarzilli 已提交
232 233 234
	}
}

D
Derek Parker 已提交
235
// ConvertLocation converts from proc.Location to api.Location.
A
aarzilli 已提交
236 237 238
func ConvertLocation(loc proc.Location) Location {
	return Location{
		PC:       loc.PC,
239
		File:     loc.File,
A
aarzilli 已提交
240 241
		Line:     loc.Line,
		Function: ConvertFunction(loc.Fn),
242 243
	}
}
A
aarzilli 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259

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,
	}
}
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285

func LoadConfigToProc(cfg *LoadConfig) *proc.LoadConfig {
	if cfg == nil {
		return nil
	}
	return &proc.LoadConfig{
		cfg.FollowPointers,
		cfg.MaxVariableRecurse,
		cfg.MaxStringLen,
		cfg.MaxArrayValues,
		cfg.MaxStructFields,
	}
}

func LoadConfigFromProc(cfg *proc.LoadConfig) *LoadConfig {
	if cfg == nil {
		return nil
	}
	return &LoadConfig{
		cfg.FollowPointers,
		cfg.MaxVariableRecurse,
		cfg.MaxStringLen,
		cfg.MaxArrayValues,
		cfg.MaxStructFields,
	}
}
A
aarzilli 已提交
286 287 288 289 290 291 292 293

func ConvertRegisters(in []proc.Register) (out []Register) {
	out = make([]Register, len(in))
	for i := range in {
		out[i] = Register{in[i].Name, in[i].Value}
	}
	return
}
294 295

func ConvertCheckpoint(in proc.Checkpoint) (out Checkpoint) {
296
	return Checkpoint(in)
297
}