variables.go 22.4 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 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
// Returns the address of the named variable
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:]
	}

	addr, err := scope.extractVarInfo(varName)
	if err != nil {
		origErr := err
		// Attempt to evaluate name as a package variable.
		if memberName != "" {
			addr, err = scope.packageVarAddr(name)
		} else {
			_, _, fn := scope.Thread.dbp.PCToLine(scope.PC)
			if fn != nil {
				addr, err = scope.packageVarAddr(fn.PackageName() + "." + name)
			}
		}
		if err != nil {
			return nil, origErr
		}
		addr.Name = name
	} else {
		if len(memberName) > 0 {
			addr, err = addr.structMember(memberName)
			if err != nil {
				return nil, err
			}
		}
	}
	return addr, nil
}

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

340 341 342
func (scope *EvalScope) extractVariableFromEntry(entry *dwarf.Entry) (*Variable, error) {
	rdr := scope.DwarfReader()
	addr, err := scope.extractVarInfoFromEntry(entry, rdr)
343
	if err != nil {
D
Derek Parker 已提交
344 345
		return nil, err
	}
346 347 348
	err = addr.loadValue(true)
	return addr, err
}
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 411 412 413 414 415 416 417 418 419
	addr, err := scope.packageVarAddr(name)
	if err != nil {
		return nil, err
	}
	err = addr.loadValue(true)
	return addr, err
}

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 502 503
// If addr is a pointer a new variable is returned containing the value pointed by addr
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 519 520
// Returns a VarAddr with the same address but a concrete dwarfType
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 533 534 535 536 537 538 539 540
	r := *v
	r.dwarfType = typ
	return &r
}

// Extracts the value of the given address
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 578 579 580
					var err error
					var val string
					var fieldvar *Variable

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

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

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

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

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

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

	count := strlen
	if count > maxArrayValues {
		count = maxArrayValues
	}
646 647

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

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

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

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

	return retstr, nil
669 670
}

671 672
func (v *Variable) loadSliceInfo(t *dwarf.StructType) error {
	var err error
E
epipho 已提交
673 674 675
	for _, f := range t.Field {
		switch f.Name {
		case "array":
676 677 678 679 680 681 682 683 684 685
			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 已提交
686 687
			}
		case "len":
688 689 690
			lstrAddr, err := v.toField(f)
			if err == nil {
				err = lstrAddr.loadValue(true)
E
epipho 已提交
691
			}
692 693
			if err == nil {
				v.Len, err = strconv.ParseInt(lstrAddr.Value, 10, 64)
E
epipho 已提交
694 695
			}
		case "cap":
696 697 698
			cstrAddr, err := v.toField(f)
			if err == nil {
				err = cstrAddr.loadValue(true)
E
epipho 已提交
699
			}
700 701
			if err == nil {
				v.Cap, err = strconv.ParseInt(cstrAddr.Value, 10, 64)
E
epipho 已提交
702 703 704 705
			}
		}
	}

706
	if err != nil {
707
		return nil
708 709
	}

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

	return nil
716 717
}

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

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

729 730 731 732 733
		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 已提交
734
		if err != nil {
735 736
			errcount++
			val = fmt.Sprintf("<unreadable: %s>", err.Error())
E
epipho 已提交
737
		}
738

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

	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
	}
751 752
}

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

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

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

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

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

D
Derek Parker 已提交
803
	return n, nil
E
epipho 已提交
804 805
}

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

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

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

	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 已提交
833
	return n, nil
834 835
}

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

D
Derek Parker 已提交
843 844 845 846 847 848 849 850 851 852 853
	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 已提交
854
	return "", fmt.Errorf("could not read float")
855 856
}

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

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

	return "true", nil
}

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

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

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

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

893
	return fn.Name, nil
894 895
}

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

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

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

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

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

			vars = append(vars, val)
		}
	}

	return vars, nil
}