variables.go 22.3 KB
Newer Older
D
Derek Parker 已提交
1
package proc
2 3 4

import (
	"bytes"
D
Derek Parker 已提交
5
	"debug/dwarf"
6
	"debug/gosym"
7 8 9 10 11 12 13
	"encoding/binary"
	"fmt"
	"strconv"
	"strings"
	"unsafe"

	"github.com/derekparker/delve/dwarf/op"
14
	"github.com/derekparker/delve/dwarf/reader"
15 16
)

17
const (
18 19
	maxVariableRecurse = 1  // How far to recurse when evaluating nested types.
	maxArrayValues     = 64 // Max value for reading large arrays.
20
	maxErrCount        = 3  // Max number of read errors to accept while evaluating slices, arrays and structs
21 22 23

	ChanRecv = "chan receive"
	ChanSend = "chan send"
24 25
)

26
// Represents a variable.
27
type Variable struct {
28 29 30 31 32 33 34 35 36 37 38 39
	Addr      uintptr
	Name      string
	Value     string
	Type      string
	dwarfType dwarf.Type
	thread    *Thread

	Len       int64
	Cap       int64
	base      uintptr
	stride    int64
	fieldType dwarf.Type
40 41
}

42
// Represents a runtime M (OS thread) structure.
43
type M struct {
44 45 46 47
	procid   int     // Thread ID or port.
	spinning uint8   // Busy looping.
	blocked  uint8   // Waiting on futex / semaphore.
	curg     uintptr // Current G running on this thread.
48 49
}

50 51 52 53 54 55 56 57 58 59 60 61 62
const (
	// G status, from: src/runtime/runtime2.go
	Gidle            uint64 = iota // 0
	Grunnable                      // 1 runnable and on a run queue
	Grunning                       // 2
	Gsyscall                       // 3
	Gwaiting                       // 4
	Gmoribund_unused               // 5 currently unused, but hardcoded in gdb scripts
	Gdead                          // 6
	Genqueue                       // 7 Only the Gscanenqueue is used.
	Gcopystack                     // 8 in this state when newstack is moving the stack
)

63 64
// Represents a runtime G (goroutine) structure (at least the
// fields that Delve is interested in).
D
Derek Parker 已提交
65
type G struct {
66 67 68 69 70
	Id         int    // Goroutine ID
	PC         uint64 // PC of goroutine when it was parked.
	SP         uint64 // SP of goroutine when it was parked.
	GoPC       uint64 // PC of 'go' statement that created this goroutine.
	WaitReason string // Reason for goroutine being parked.
71
	Status     uint64
72 73 74 75 76

	// Information on goroutine location.
	File string
	Line int
	Func *gosym.Func
77 78 79

	// PC of entry to top-most deferred function.
	DeferPC uint64
A
aarzilli 已提交
80 81 82

	// Thread that this goroutine is currently allocated to
	thread *Thread
83 84
}

85 86 87 88 89 90 91
// Scope for variable evaluation
type EvalScope struct {
	Thread *Thread
	PC     uint64
	CFA    int64
}

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
func newVariable(name string, addr uintptr, dwarfType dwarf.Type, thread *Thread) (*Variable, error) {
	v := &Variable{
		Name:      name,
		Addr:      addr,
		dwarfType: dwarfType,
		thread:    thread,
		Type:      dwarfType.String(),
	}

	switch t := dwarfType.(type) {
	case *dwarf.StructType:
		if strings.HasPrefix(t.StructName, "[]") {
			err := v.loadSliceInfo(t)
			if err != nil {
				return nil, err
			}
		}
	case *dwarf.ArrayType:
		v.base = v.Addr
		v.Len = t.Count
		v.Cap = -1
		v.fieldType = t.Type
		v.stride = 0

		if t.Count > 0 {
			v.stride = t.ByteSize / t.Count
		}
	}

	return v, nil
}

func (v *Variable) toField(field *dwarf.StructField) (*Variable, error) {
	name := ""
	if v.Name != "" {
		name = fmt.Sprintf("%s.%s", v.Name, field.Name)
	}
	return newVariable(name, uintptr(int64(v.Addr)+field.ByteOffset), field.Type, v.thread)
}

132 133 134 135 136 137 138 139 140 141 142 143
func (scope *EvalScope) DwarfReader() *reader.Reader {
	return scope.Thread.dbp.DwarfReader()
}

func (scope *EvalScope) Type(offset dwarf.Offset) (dwarf.Type, error) {
	return scope.Thread.dbp.dwarf.Type(offset)
}

func (scope *EvalScope) PtrSize() int {
	return scope.Thread.dbp.arch.PtrSize()
}

144 145
// Returns whether the goroutine is blocked on
// a channel read operation.
146 147 148 149 150
func (g *G) ChanRecvBlocked() bool {
	return g.WaitReason == ChanRecv
}

// chanRecvReturnAddr returns the address of the return from a channel read.
D
Derek Parker 已提交
151
func (g *G) chanRecvReturnAddr(dbp *Process) (uint64, error) {
152 153 154 155 156
	locs, err := dbp.stacktrace(g.PC, g.SP, 4)
	if err != nil {
		return 0, err
	}
	topLoc := locs[len(locs)-1]
157
	return topLoc.Current.PC, nil
D
Derek Parker 已提交
158 159
}

D
Derek Parker 已提交
160 161
// NoGError returned when a G could not be found
// for a specific thread.
162 163 164 165 166 167 168 169
type NoGError struct {
	tid int
}

func (ng NoGError) Error() string {
	return fmt.Sprintf("no G executing on thread %d", ng.tid)
}

D
Derek Parker 已提交
170
func parseG(thread *Thread, gaddr uint64, deref bool) (*G, error) {
171 172 173 174 175 176 177 178 179 180 181 182 183
	initialInstructions := make([]byte, thread.dbp.arch.PtrSize()+1)
	initialInstructions[0] = op.DW_OP_addr
	binary.LittleEndian.PutUint64(initialInstructions[1:], gaddr)
	if deref {
		gaddrbytes, err := thread.readMemory(uintptr(gaddr), thread.dbp.arch.PtrSize())
		if err != nil {
			return nil, fmt.Errorf("error derefing *G %s", err)
		}
		initialInstructions = append([]byte{op.DW_OP_addr}, gaddrbytes...)
		gaddr = binary.LittleEndian.Uint64(gaddrbytes)
		if gaddr == 0 {
			return nil, NoGError{tid: thread.Id}
		}
184
	}
185

186
	rdr := thread.dbp.DwarfReader()
D
Derek Parker 已提交
187
	rdr.Seek(0)
188
	entry, err := rdr.SeekToTypeNamed("runtime.g")
189 190 191
	if err != nil {
		return nil, err
	}
D
Derek Parker 已提交
192

193 194 195 196 197 198 199
	// Parse defer
	deferAddr, err := rdr.AddrForMember("_defer", initialInstructions)
	if err != nil {
		return nil, err
	}
	var deferPC uint64
	// Dereference *defer pointer
200
	deferAddrBytes, err := thread.readMemory(uintptr(deferAddr), thread.dbp.arch.PtrSize())
201
	if err != nil {
202
		return nil, fmt.Errorf("error derefing defer %s", err)
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
	}
	if binary.LittleEndian.Uint64(deferAddrBytes) != 0 {
		initialDeferInstructions := append([]byte{op.DW_OP_addr}, deferAddrBytes...)
		_, err = rdr.SeekToTypeNamed("runtime._defer")
		if err != nil {
			return nil, err
		}
		deferPCAddr, err := rdr.AddrForMember("fn", initialDeferInstructions)
		deferPC, err = thread.readUintRaw(uintptr(deferPCAddr), 8)
		if err != nil {
			return nil, err
		}
		deferPC, err = thread.readUintRaw(uintptr(deferPC), 8)
		if err != nil {
			return nil, err
		}
	}
220 221 222 223 224 225 226 227 228

	// Let's parse all of the members we care about in order so that
	// we don't have to spend any extra time seeking.

	err = rdr.SeekToEntry(entry)
	if err != nil {
		return nil, err
	}

D
Derek Parker 已提交
229 230
	// Parse sched
	schedAddr, err := rdr.AddrForMember("sched", initialInstructions)
231
	if err != nil {
D
Derek Parker 已提交
232
		return nil, err
233
	}
D
Derek Parker 已提交
234 235
	// From sched, let's parse PC and SP.
	sp, err := thread.readUintRaw(uintptr(schedAddr), 8)
236
	if err != nil {
D
Derek Parker 已提交
237
		return nil, err
238
	}
239
	pc, err := thread.readUintRaw(uintptr(schedAddr+uint64(thread.dbp.arch.PtrSize())), 8)
240
	if err != nil {
D
Derek Parker 已提交
241
		return nil, err
242
	}
243 244 245 246 247 248
	// Parse atomicstatus
	atomicStatusAddr, err := rdr.AddrForMember("atomicstatus", initialInstructions)
	if err != nil {
		return nil, err
	}
	atomicStatus, err := thread.readUintRaw(uintptr(atomicStatusAddr), 4)
D
Derek Parker 已提交
249 250
	// Parse goid
	goidAddr, err := rdr.AddrForMember("goid", initialInstructions)
251 252 253
	if err != nil {
		return nil, err
	}
D
Derek Parker 已提交
254
	goid, err := thread.readIntRaw(uintptr(goidAddr), 8)
255 256 257
	if err != nil {
		return nil, err
	}
D
Derek Parker 已提交
258 259
	// Parse waitreason
	waitReasonAddr, err := rdr.AddrForMember("waitreason", initialInstructions)
260
	if err != nil {
D
Derek Parker 已提交
261
		return nil, err
262
	}
D
Derek Parker 已提交
263
	waitreason, err := thread.readString(uintptr(waitReasonAddr))
264
	if err != nil {
D
Derek Parker 已提交
265
		return nil, err
266
	}
D
Derek Parker 已提交
267 268
	// Parse gopc
	gopcAddr, err := rdr.AddrForMember("gopc", initialInstructions)
269
	if err != nil {
D
Derek Parker 已提交
270 271 272 273 274
		return nil, err
	}
	gopc, err := thread.readUintRaw(uintptr(gopcAddr), 8)
	if err != nil {
		return nil, err
275
	}
276

277
	f, l, fn := thread.dbp.goSymTable.PCToLine(pc)
278
	g := &G{
D
Derek Parker 已提交
279 280 281 282
		Id:         int(goid),
		GoPC:       gopc,
		PC:         pc,
		SP:         sp,
283 284 285 286
		File:       f,
		Line:       l,
		Func:       fn,
		WaitReason: waitreason,
287
		DeferPC:    deferPC,
288
		Status:     atomicStatus,
289 290
	}
	return g, nil
291 292
}

293
// Returns information for the named variable.
294 295 296 297 298 299 300 301 302
func (scope *EvalScope) ExtractVariableInfo(name string) (*Variable, error) {
	varName := name
	memberName := ""
	if strings.Contains(name, ".") {
		idx := strings.Index(name, ".")
		varName = name[:idx]
		memberName = name[idx+1:]
	}

303
	v, err := scope.extractVarInfo(varName)
304 305 306 307
	if err != nil {
		origErr := err
		// Attempt to evaluate name as a package variable.
		if memberName != "" {
308
			v, err = scope.packageVarAddr(name)
309 310 311
		} else {
			_, _, fn := scope.Thread.dbp.PCToLine(scope.PC)
			if fn != nil {
312
				v, err = scope.packageVarAddr(fn.PackageName() + "." + name)
313 314 315 316 317
			}
		}
		if err != nil {
			return nil, origErr
		}
318
		v.Name = name
319 320
	} else {
		if len(memberName) > 0 {
321
			v, err = v.structMember(memberName)
322 323 324 325 326
			if err != nil {
				return nil, err
			}
		}
	}
327
	return v, nil
328 329
}

330
// Returns the value of the named variable.
331
func (scope *EvalScope) EvalVariable(name string) (*Variable, error) {
332
	v, err := scope.ExtractVariableInfo(name)
333 334 335
	if err != nil {
		return nil, err
	}
336 337
	err = v.loadValue(true)
	return v, err
338
}
339

340 341
func (scope *EvalScope) extractVariableFromEntry(entry *dwarf.Entry) (*Variable, error) {
	rdr := scope.DwarfReader()
342
	v, err := scope.extractVarInfoFromEntry(entry, rdr)
343
	if err != nil {
D
Derek Parker 已提交
344 345
		return nil, err
	}
346 347
	err = v.loadValue(true)
	return v, err
348
}
D
Derek Parker 已提交
349

350 351 352 353 354 355
func (scope *EvalScope) extractVarInfo(varName string) (*Variable, error) {
	reader := scope.DwarfReader()

	_, err := reader.SeekToFunction(scope.PC)
	if err != nil {
		return nil, err
356 357
	}

358
	for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() {
D
Derek Parker 已提交
359
		if err != nil {
360
			return nil, err
D
Derek Parker 已提交
361 362 363 364 365 366 367
		}

		n, ok := entry.Val(dwarf.AttrName).(string)
		if !ok {
			continue
		}

368
		if n == varName {
369
			return scope.extractVarInfoFromEntry(entry, reader)
D
Derek Parker 已提交
370 371
		}
	}
372
	return nil, fmt.Errorf("could not find symbol value for %s", varName)
D
Derek Parker 已提交
373
}
374

375
// LocalVariables returns all local variables from the current function scope.
376 377
func (scope *EvalScope) LocalVariables() ([]*Variable, error) {
	return scope.variablesByTag(dwarf.TagVariable)
378 379 380
}

// FunctionArguments returns the name, value, and type of all current function arguments.
381 382
func (scope *EvalScope) FunctionArguments() ([]*Variable, error) {
	return scope.variablesByTag(dwarf.TagFormalParameter)
383 384 385
}

// PackageVariables returns the name, value, and type of all package variables in the application.
386 387
func (scope *EvalScope) PackageVariables() ([]*Variable, error) {
	reader := scope.DwarfReader()
388 389 390 391 392 393 394 395 396

	vars := make([]*Variable, 0)

	for entry, err := reader.NextPackageVariable(); entry != nil; entry, err = reader.NextPackageVariable() {
		if err != nil {
			return nil, err
		}

		// Ignore errors trying to extract values
397
		val, err := scope.extractVariableFromEntry(entry)
398 399 400 401 402 403 404 405 406
		if err != nil {
			continue
		}
		vars = append(vars, val)
	}

	return vars, nil
}

407 408
func (dbp *Process) EvalPackageVariable(name string) (*Variable, error) {
	scope := &EvalScope{Thread: dbp.CurrentThread, PC: 0, CFA: 0}
409

410
	v, err := scope.packageVarAddr(name)
411 412 413
	if err != nil {
		return nil, err
	}
414 415
	err = v.loadValue(true)
	return v, err
416 417 418 419
}

func (scope *EvalScope) packageVarAddr(name string) (*Variable, error) {
	reader := scope.DwarfReader()
420 421 422 423 424 425 426 427 428 429 430
	for entry, err := reader.NextPackageVariable(); entry != nil; entry, err = reader.NextPackageVariable() {
		if err != nil {
			return nil, err
		}

		n, ok := entry.Val(dwarf.AttrName).(string)
		if !ok {
			continue
		}

		if n == name {
431
			return scope.extractVarInfoFromEntry(entry, reader)
432 433 434 435 436
		}
	}
	return nil, fmt.Errorf("could not find symbol value for %s", name)
}

437 438 439
func (v *Variable) structMember(memberName string) (*Variable, error) {
	structVar, err := v.maybeDereference()
	structVar.Name = v.Name
440 441 442
	if err != nil {
		return nil, err
	}
443
	structVar = structVar.resolveTypedefs()
444

445 446 447 448 449
	switch t := structVar.dwarfType.(type) {
	case *dwarf.StructType:
		for _, field := range t.Field {
			if field.Name != memberName {
				continue
450
			}
451 452
			if structVar.Addr == 0 {
				return nil, fmt.Errorf("%s is nil", v.Name)
453
			}
454
			return structVar.toField(field)
455
		}
456 457 458
		return nil, fmt.Errorf("%s has no member %s", v.Name, memberName)
	default:
		return nil, fmt.Errorf("%s type %s is not a struct", v.Name, structVar.dwarfType)
459
	}
460 461
}

462 463 464
// Extracts the name and type of a variable from a dwarf entry
// then executes the instructions given in the  DW_AT_location attribute to grab the variable's address
func (scope *EvalScope) extractVarInfoFromEntry(entry *dwarf.Entry, rdr *reader.Reader) (*Variable, error) {
E
epipho 已提交
465
	if entry == nil {
D
Derek Parker 已提交
466
		return nil, fmt.Errorf("invalid entry")
E
epipho 已提交
467 468 469 470 471 472 473 474
	}

	if entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagVariable {
		return nil, fmt.Errorf("invalid entry tag, only supports FormalParameter and Variable, got %s", entry.Tag.String())
	}

	n, ok := entry.Val(dwarf.AttrName).(string)
	if !ok {
D
Derek Parker 已提交
475
		return nil, fmt.Errorf("type assertion failed")
E
epipho 已提交
476 477 478 479
	}

	offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
	if !ok {
D
Derek Parker 已提交
480
		return nil, fmt.Errorf("type assertion failed")
E
epipho 已提交
481 482
	}

483
	t, err := scope.Type(offset)
E
epipho 已提交
484 485 486 487 488 489
	if err != nil {
		return nil, err
	}

	instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
	if !ok {
D
Derek Parker 已提交
490
		return nil, fmt.Errorf("type assertion failed")
E
epipho 已提交
491 492
	}

493
	addr, err := op.ExecuteStackProgram(scope.CFA, instructions)
E
epipho 已提交
494 495 496 497
	if err != nil {
		return nil, err
	}

498
	return newVariable(n, uintptr(addr), t, scope.Thread)
E
epipho 已提交
499 500
}

501
// If v is a pointer a new variable is returned containing the value pointed by v.
502 503
func (v *Variable) maybeDereference() (*Variable, error) {
	v = v.resolveTypedefs()
504

505 506 507
	switch t := v.dwarfType.(type) {
	case *dwarf.PtrType:
		ptrval, err := v.thread.readUintRaw(uintptr(v.Addr), int64(v.thread.dbp.arch.PtrSize()))
508
		if err != nil {
509
			return nil, err
510 511
		}

512 513 514
		return newVariable("", uintptr(ptrval), t.Type, v.thread)
	default:
		return v, nil
515 516
	}
}
517

518
// Returns a Variable with the same address but a concrete dwarfType.
519 520
func (v *Variable) resolveTypedefs() *Variable {
	typ := v.dwarfType
521 522 523 524 525 526
	for {
		if tt, ok := typ.(*dwarf.TypedefType); ok {
			typ = tt.Type
		} else {
			break
		}
527
	}
528 529 530 531 532
	r := *v
	r.dwarfType = typ
	return &r
}

533
// Extracts the value of the variable at the given address.
534 535 536 537 538 539 540
func (v *Variable) loadValue(printStructName bool) (err error) {
	v.Value, err = v.loadValueInternal(printStructName, 0)
	return
}

func (v *Variable) loadValueInternal(printStructName bool, recurseLevel int) (string, error) {
	v = v.resolveTypedefs()
541

542
	switch t := v.dwarfType.(type) {
543
	case *dwarf.PtrType:
544
		ptrv, err := v.maybeDereference()
545 546 547
		if err != nil {
			return "", err
		}
548

549
		if ptrv.Addr == 0 {
550 551 552
			return fmt.Sprintf("%s nil", t.String()), nil
		}

553
		// Don't increase the recursion level when dereferencing pointers
554
		val, err := ptrv.loadValueInternal(printStructName, recurseLevel)
555 556 557 558
		if err != nil {
			return "", err
		}

559
		return fmt.Sprintf("*%s", val), nil
560
	case *dwarf.StructType:
E
epipho 已提交
561 562
		switch {
		case t.StructName == "string":
563
			return v.thread.readString(uintptr(v.Addr))
E
epipho 已提交
564
		case strings.HasPrefix(t.StructName, "[]"):
565
			return v.loadArrayValues(recurseLevel)
566
		default:
D
Derek Parker 已提交
567
			// Recursively call extractValue to grab
568
			// the value of all the members of the struct.
569
			if recurseLevel <= maxVariableRecurse {
570
				errcount := 0
571
				fields := make([]string, 0, len(t.Field))
572
				for i, field := range t.Field {
573 574 575 576 577
					var (
						err      error
						val      string
						fieldvar *Variable
					)
578 579 580 581 582

					fieldvar, err = v.toField(field)
					if err == nil {
						val, err = fieldvar.loadValueInternal(printStructName, recurseLevel+1)
					}
583
					if err != nil {
584 585
						errcount++
						val = fmt.Sprintf("<unreadable: %s>", err.Error())
586 587 588
					}

					fields = append(fields, fmt.Sprintf("%s: %s", field.Name, val))
589 590 591 592

					if errcount > maxErrCount {
						fields = append(fields, fmt.Sprintf("...+%d more", len(t.Field)-i))
					}
593
				}
594 595 596 597
				if printStructName {
					return fmt.Sprintf("%s {%s}", t.StructName, strings.Join(fields, ", ")), nil
				}
				return fmt.Sprintf("{%s}", strings.Join(fields, ", ")), nil
598
			}
599
			// no fields
E
epipho 已提交
600
			if printStructName {
601
				return fmt.Sprintf("%s {...}", t.StructName), nil
E
epipho 已提交
602
			}
603
			return "{...}", nil
604 605
		}
	case *dwarf.ArrayType:
606
		return v.loadArrayValues(recurseLevel)
607
	case *dwarf.ComplexType:
608
		return v.readComplex(t.ByteSize)
609
	case *dwarf.IntType:
610
		return v.readInt(t.ByteSize)
E
epipho 已提交
611
	case *dwarf.UintType:
612
		return v.readUint(t.ByteSize)
613
	case *dwarf.FloatType:
614
		return v.readFloat(t.ByteSize)
E
epipho 已提交
615
	case *dwarf.BoolType:
616
		return v.readBool()
617
	case *dwarf.FuncType:
618
		return v.readFunctionPtr()
619 620 621 622
	case *dwarf.VoidType:
		return "(void)", nil
	case *dwarf.UnspecifiedType:
		return "(unknown)", nil
623 624
	default:
		fmt.Printf("Unknown type: %T\n", t)
625 626
	}

627
	return "", fmt.Errorf("could not find value for type %s", v.dwarfType)
628 629
}

D
Derek Parker 已提交
630
func (thread *Thread) readString(addr uintptr) (string, error) {
631 632 633 634
	// string data structure is always two ptrs in size. Addr, followed by len
	// http://research.swtch.com/godata

	// read len
635
	val, err := thread.readMemory(addr+uintptr(thread.dbp.arch.PtrSize()), thread.dbp.arch.PtrSize())
636
	if err != nil {
637
		return "", fmt.Errorf("could not read string len %s", err)
638
	}
639
	strlen := int(binary.LittleEndian.Uint64(val))
640 641 642 643 644 645 646 647
	if strlen < 0 {
		return "", fmt.Errorf("invalid length: %d", strlen)
	}

	count := strlen
	if count > maxArrayValues {
		count = maxArrayValues
	}
648 649

	// read addr
650
	val, err = thread.readMemory(addr, thread.dbp.arch.PtrSize())
651
	if err != nil {
652
		return "", fmt.Errorf("could not read string pointer %s", err)
653 654
	}
	addr = uintptr(binary.LittleEndian.Uint64(val))
D
Derek Parker 已提交
655 656 657
	if addr == 0 {
		return "", nil
	}
D
Derek Parker 已提交
658

659
	val, err = thread.readMemory(addr, count)
660
	if err != nil {
661
		return "", fmt.Errorf("could not read string at %#v due to %s", addr, err)
662 663
	}

664 665 666 667 668 669 670
	retstr := *(*string)(unsafe.Pointer(&val))

	if count != strlen {
		retstr = retstr + fmt.Sprintf("...+%d more", strlen-count)
	}

	return retstr, nil
671 672
}

673 674
func (v *Variable) loadSliceInfo(t *dwarf.StructType) error {
	var err error
E
epipho 已提交
675 676 677
	for _, f := range t.Field {
		switch f.Name {
		case "array":
678 679 680 681 682 683 684 685 686 687
			var base uint64
			base, err = v.thread.readUintRaw(uintptr(int64(v.Addr)+f.ByteOffset), int64(v.thread.dbp.arch.PtrSize()))
			if err == nil {
				v.base = uintptr(base)
				// Dereference array type to get value type
				ptrType, ok := f.Type.(*dwarf.PtrType)
				if !ok {
					return fmt.Errorf("Invalid type %s in slice array", f.Type)
				}
				v.fieldType = ptrType.Type
E
epipho 已提交
688 689
			}
		case "len":
690 691 692
			lstrAddr, err := v.toField(f)
			if err == nil {
				err = lstrAddr.loadValue(true)
E
epipho 已提交
693
			}
694 695
			if err == nil {
				v.Len, err = strconv.ParseInt(lstrAddr.Value, 10, 64)
E
epipho 已提交
696 697
			}
		case "cap":
698 699 700
			cstrAddr, err := v.toField(f)
			if err == nil {
				err = cstrAddr.loadValue(true)
E
epipho 已提交
701
			}
702 703
			if err == nil {
				v.Cap, err = strconv.ParseInt(cstrAddr.Value, 10, 64)
E
epipho 已提交
704 705 706 707
			}
		}
	}

708
	if err != nil {
709
		return nil
710 711
	}

712 713 714
	v.stride = v.fieldType.Size()
	if _, ok := v.fieldType.(*dwarf.PtrType); ok {
		v.stride = int64(v.thread.dbp.arch.PtrSize())
715
	}
716 717

	return nil
718 719
}

720
func (v *Variable) loadArrayValues(recurseLevel int) (string, error) {
E
epipho 已提交
721
	vals := make([]string, 0)
722
	errcount := 0
723

724
	for i := int64(0); i < v.Len; i++ {
725 726
		// Cap number of elements
		if i >= maxArrayValues {
727
			vals = append(vals, fmt.Sprintf("...+%d more", v.Len-maxArrayValues))
728 729 730
			break
		}

731 732 733 734 735
		var val string
		fieldvar, err := newVariable("", uintptr(int64(v.base)+(i*v.stride)), v.fieldType, v.thread)
		if err == nil {
			val, err = fieldvar.loadValueInternal(false, recurseLevel+1)
		}
E
epipho 已提交
736
		if err != nil {
737 738
			errcount++
			val = fmt.Sprintf("<unreadable: %s>", err.Error())
E
epipho 已提交
739
		}
740

E
epipho 已提交
741
		vals = append(vals, val)
742
		if errcount > maxErrCount {
743
			vals = append(vals, fmt.Sprintf("...+%d more", v.Len-i))
744 745
			break
		}
746
	}
747 748 749 750 751 752

	if v.Cap < 0 {
		return fmt.Sprintf("%s [%s]", v.dwarfType, strings.Join(vals, ",")), nil
	} else {
		return fmt.Sprintf("[]%s len: %d, cap: %d, [%s]", v.fieldType, v.Len, v.Cap, strings.Join(vals, ",")), nil
	}
753 754
}

755
func (v *Variable) readComplex(size int64) (string, error) {
756 757 758 759 760 761 762 763 764
	var fs int64
	switch size {
	case 8:
		fs = 4
	case 16:
		fs = 8
	default:
		return "", fmt.Errorf("invalid size (%d) for complex type", size)
	}
765
	r, err := v.readFloat(fs)
766 767 768
	if err != nil {
		return "", err
	}
769 770 771
	imagvar := *v
	imagvar.Addr += uintptr(fs)
	i, err := imagvar.readFloat(fs)
772 773 774
	if err != nil {
		return "", err
	}
775
	return fmt.Sprintf("(%s + %si)", r, i), nil
776 777
}

778 779
func (v *Variable) readInt(size int64) (string, error) {
	n, err := v.thread.readIntRaw(v.Addr, size)
D
Derek Parker 已提交
780 781 782 783 784 785
	if err != nil {
		return "", err
	}
	return strconv.FormatInt(n, 10), nil
}

D
Derek Parker 已提交
786
func (thread *Thread) readIntRaw(addr uintptr, size int64) (int64, error) {
E
epipho 已提交
787
	var n int64
788

789
	val, err := thread.readMemory(addr, int(size))
790
	if err != nil {
D
Derek Parker 已提交
791
		return 0, err
792 793
	}

794 795
	switch size {
	case 1:
E
epipho 已提交
796
		n = int64(val[0])
797
	case 2:
E
epipho 已提交
798
		n = int64(binary.LittleEndian.Uint16(val))
799
	case 4:
E
epipho 已提交
800
		n = int64(binary.LittleEndian.Uint32(val))
801
	case 8:
E
epipho 已提交
802
		n = int64(binary.LittleEndian.Uint64(val))
803
	}
804

D
Derek Parker 已提交
805
	return n, nil
E
epipho 已提交
806 807
}

808 809
func (v *Variable) readUint(size int64) (string, error) {
	n, err := v.thread.readUintRaw(v.Addr, size)
D
Derek Parker 已提交
810 811 812 813 814 815
	if err != nil {
		return "", err
	}
	return strconv.FormatUint(n, 10), nil
}

D
Derek Parker 已提交
816
func (thread *Thread) readUintRaw(addr uintptr, size int64) (uint64, error) {
E
epipho 已提交
817 818
	var n uint64

819
	val, err := thread.readMemory(addr, int(size))
E
epipho 已提交
820
	if err != nil {
D
Derek Parker 已提交
821
		return 0, err
E
epipho 已提交
822 823 824 825 826 827 828 829 830 831 832 833 834
	}

	switch size {
	case 1:
		n = uint64(val[0])
	case 2:
		n = uint64(binary.LittleEndian.Uint16(val))
	case 4:
		n = uint64(binary.LittleEndian.Uint32(val))
	case 8:
		n = uint64(binary.LittleEndian.Uint64(val))
	}

D
Derek Parker 已提交
835
	return n, nil
836 837
}

838 839
func (v *Variable) readFloat(size int64) (string, error) {
	val, err := v.thread.readMemory(v.Addr, int(size))
840 841 842 843 844
	if err != nil {
		return "", err
	}
	buf := bytes.NewBuffer(val)

D
Derek Parker 已提交
845 846 847 848 849 850 851 852 853 854 855
	switch size {
	case 4:
		n := float32(0)
		binary.Read(buf, binary.LittleEndian, &n)
		return strconv.FormatFloat(float64(n), 'f', -1, int(size)*8), nil
	case 8:
		n := float64(0)
		binary.Read(buf, binary.LittleEndian, &n)
		return strconv.FormatFloat(n, 'f', -1, int(size)*8), nil
	}

D
Derek Parker 已提交
856
	return "", fmt.Errorf("could not read float")
857 858
}

859 860
func (v *Variable) readBool() (string, error) {
	val, err := v.thread.readMemory(v.Addr, 1)
E
epipho 已提交
861 862 863 864 865 866 867 868 869 870 871
	if err != nil {
		return "", err
	}

	if val[0] == 0 {
		return "false", nil
	}

	return "true", nil
}

872 873
func (v *Variable) readFunctionPtr() (string, error) {
	val, err := v.thread.readMemory(v.Addr, v.thread.dbp.arch.PtrSize())
874 875 876 877 878
	if err != nil {
		return "", err
	}

	// dereference pointer to find function pc
879 880
	fnaddr := uintptr(binary.LittleEndian.Uint64(val))
	if fnaddr == 0 {
881 882
		return "nil", nil
	}
883

884
	val, err = v.thread.readMemory(fnaddr, v.thread.dbp.arch.PtrSize())
885 886 887 888 889
	if err != nil {
		return "", err
	}

	funcAddr := binary.LittleEndian.Uint64(val)
890
	fn := v.thread.dbp.goSymTable.PCToFunc(uint64(funcAddr))
891 892
	if fn == nil {
		return "", fmt.Errorf("could not find function for %#v", funcAddr)
893 894
	}

895
	return fn.Name, nil
896 897
}

E
epipho 已提交
898
// Fetches all variables of a specific type in the current function scope
899 900
func (scope *EvalScope) variablesByTag(tag dwarf.Tag) ([]*Variable, error) {
	reader := scope.DwarfReader()
E
epipho 已提交
901

902
	_, err := reader.SeekToFunction(scope.PC)
903
	if err != nil {
E
epipho 已提交
904 905 906 907 908
		return nil, err
	}

	vars := make([]*Variable, 0)

909
	for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() {
E
epipho 已提交
910 911 912 913 914
		if err != nil {
			return nil, err
		}

		if entry.Tag == tag {
915
			val, err := scope.extractVariableFromEntry(entry)
E
epipho 已提交
916
			if err != nil {
E
epipho 已提交
917 918
				// skip variables that we can't parse yet
				continue
E
epipho 已提交
919 920 921 922 923 924 925 926
			}

			vars = append(vars, val)
		}
	}

	return vars, nil
}