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 21 22

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

25
// Represents an evaluated variable.
26 27 28 29 30 31
type Variable struct {
	Name  string
	Value string
	Type  string
}

32
// Represents a runtime M (OS thread) structure.
33
type M struct {
34 35 36 37
	procid   int     // Thread ID or port.
	spinning uint8   // Busy looping.
	blocked  uint8   // Waiting on futex / semaphore.
	curg     uintptr // Current G running on this thread.
38 39
}

40 41 42 43 44 45 46 47 48 49 50 51 52
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
)

53 54
// Represents a runtime G (goroutine) structure (at least the
// fields that Delve is interested in).
D
Derek Parker 已提交
55
type G struct {
56 57 58 59 60
	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.
61
	Status     uint64
62 63 64 65 66

	// Information on goroutine location.
	File string
	Line int
	Func *gosym.Func
67 68 69

	// PC of entry to top-most deferred function.
	DeferPC uint64
A
aarzilli 已提交
70 71 72

	// Thread that this goroutine is currently allocated to
	thread *Thread
73 74
}

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
// Scope for variable evaluation
type EvalScope struct {
	Thread *Thread
	PC     uint64
	CFA    int64
}

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()
}

94 95
// Returns whether the goroutine is blocked on
// a channel read operation.
96 97 98 99 100
func (g *G) ChanRecvBlocked() bool {
	return g.WaitReason == ChanRecv
}

// chanRecvReturnAddr returns the address of the return from a channel read.
D
Derek Parker 已提交
101
func (g *G) chanRecvReturnAddr(dbp *Process) (uint64, error) {
102 103 104 105 106
	locs, err := dbp.stacktrace(g.PC, g.SP, 4)
	if err != nil {
		return 0, err
	}
	topLoc := locs[len(locs)-1]
A
aarzilli 已提交
107
	return topLoc.PC, nil
D
Derek Parker 已提交
108 109
}

D
Derek Parker 已提交
110 111
// NoGError returned when a G could not be found
// for a specific thread.
112 113 114 115 116 117 118 119
type NoGError struct {
	tid int
}

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

D
Derek Parker 已提交
120
func parseG(thread *Thread, gaddr uint64, deref bool) (*G, error) {
121 122 123 124 125 126 127 128 129 130 131 132 133
	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}
		}
134
	}
135

136
	rdr := thread.dbp.DwarfReader()
D
Derek Parker 已提交
137
	rdr.Seek(0)
138
	entry, err := rdr.SeekToTypeNamed("runtime.g")
139 140 141
	if err != nil {
		return nil, err
	}
D
Derek Parker 已提交
142

143 144 145 146 147 148 149
	// Parse defer
	deferAddr, err := rdr.AddrForMember("_defer", initialInstructions)
	if err != nil {
		return nil, err
	}
	var deferPC uint64
	// Dereference *defer pointer
150
	deferAddrBytes, err := thread.readMemory(uintptr(deferAddr), thread.dbp.arch.PtrSize())
151
	if err != nil {
152
		return nil, fmt.Errorf("error derefing defer %s", err)
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
	}
	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
		}
	}
170 171 172 173 174 175 176 177 178

	// 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 已提交
179 180
	// Parse sched
	schedAddr, err := rdr.AddrForMember("sched", initialInstructions)
181
	if err != nil {
D
Derek Parker 已提交
182
		return nil, err
183
	}
D
Derek Parker 已提交
184 185
	// From sched, let's parse PC and SP.
	sp, err := thread.readUintRaw(uintptr(schedAddr), 8)
186
	if err != nil {
D
Derek Parker 已提交
187
		return nil, err
188
	}
189
	pc, err := thread.readUintRaw(uintptr(schedAddr+uint64(thread.dbp.arch.PtrSize())), 8)
190
	if err != nil {
D
Derek Parker 已提交
191
		return nil, err
192
	}
193 194 195 196 197 198
	// Parse atomicstatus
	atomicStatusAddr, err := rdr.AddrForMember("atomicstatus", initialInstructions)
	if err != nil {
		return nil, err
	}
	atomicStatus, err := thread.readUintRaw(uintptr(atomicStatusAddr), 4)
D
Derek Parker 已提交
199 200
	// Parse goid
	goidAddr, err := rdr.AddrForMember("goid", initialInstructions)
201 202 203
	if err != nil {
		return nil, err
	}
D
Derek Parker 已提交
204
	goid, err := thread.readIntRaw(uintptr(goidAddr), 8)
205 206 207
	if err != nil {
		return nil, err
	}
D
Derek Parker 已提交
208 209
	// Parse waitreason
	waitReasonAddr, err := rdr.AddrForMember("waitreason", initialInstructions)
210
	if err != nil {
D
Derek Parker 已提交
211
		return nil, err
212
	}
D
Derek Parker 已提交
213
	waitreason, err := thread.readString(uintptr(waitReasonAddr))
214
	if err != nil {
D
Derek Parker 已提交
215
		return nil, err
216
	}
D
Derek Parker 已提交
217 218
	// Parse gopc
	gopcAddr, err := rdr.AddrForMember("gopc", initialInstructions)
219
	if err != nil {
D
Derek Parker 已提交
220 221 222 223 224
		return nil, err
	}
	gopc, err := thread.readUintRaw(uintptr(gopcAddr), 8)
	if err != nil {
		return nil, err
225
	}
226

227
	f, l, fn := thread.dbp.goSymTable.PCToLine(pc)
228
	g := &G{
D
Derek Parker 已提交
229 230 231 232
		Id:         int(goid),
		GoPC:       gopc,
		PC:         pc,
		SP:         sp,
233 234 235 236
		File:       f,
		Line:       l,
		Func:       fn,
		WaitReason: waitreason,
237
		DeferPC:    deferPC,
238
		Status:     atomicStatus,
239 240
	}
	return g, nil
241 242
}

243
// Returns the value of the named variable.
244 245
func (scope *EvalScope) EvalVariable(name string) (*Variable, error) {
	reader := scope.DwarfReader()
246

247
	_, err := reader.SeekToFunction(scope.PC)
248
	if err != nil {
D
Derek Parker 已提交
249 250
		return nil, err
	}
D
Derek Parker 已提交
251

252 253
	varName := name
	memberName := ""
254 255
	if strings.Contains(name, ".") {
		idx := strings.Index(name, ".")
256 257
		varName = name[:idx]
		memberName = name[idx+1:]
258 259
	}

260
	for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() {
D
Derek Parker 已提交
261
		if err != nil {
262
			return nil, err
D
Derek Parker 已提交
263 264 265 266 267 268 269
		}

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

270 271
		if n == varName {
			if len(memberName) == 0 {
272
				return scope.extractVariableFromEntry(entry)
273
			}
274
			return scope.evaluateStructMember(entry, reader, memberName)
D
Derek Parker 已提交
275 276 277
		}
	}

278 279
	// Attempt to evaluate name as a package variable.
	if memberName != "" {
280
		return scope.Thread.dbp.EvalPackageVariable(name)
281
	} else {
282 283 284
		_, _, fn := scope.Thread.dbp.PCToLine(scope.PC)
		if fn != nil {
			v, err := scope.Thread.dbp.EvalPackageVariable(fn.PackageName() + "." + name)
285 286 287 288 289 290 291
			if err == nil {
				v.Name = name
				return v, nil
			}
		}
	}

292
	return nil, fmt.Errorf("could not find symbol value for %s", name)
D
Derek Parker 已提交
293
}
294

295
// LocalVariables returns all local variables from the current function scope.
296 297
func (scope *EvalScope) LocalVariables() ([]*Variable, error) {
	return scope.variablesByTag(dwarf.TagVariable)
298 299 300
}

// FunctionArguments returns the name, value, and type of all current function arguments.
301 302
func (scope *EvalScope) FunctionArguments() ([]*Variable, error) {
	return scope.variablesByTag(dwarf.TagFormalParameter)
303 304 305
}

// PackageVariables returns the name, value, and type of all package variables in the application.
306 307
func (scope *EvalScope) PackageVariables() ([]*Variable, error) {
	reader := scope.DwarfReader()
308 309 310 311 312 313 314 315 316

	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
317
		val, err := scope.extractVariableFromEntry(entry)
318 319 320 321 322 323 324 325 326
		if err != nil {
			continue
		}
		vars = append(vars, val)
	}

	return vars, nil
}

327 328 329
func (dbp *Process) EvalPackageVariable(name string) (*Variable, error) {
	reader := dbp.DwarfReader()
	scope := &EvalScope{Thread: dbp.CurrentThread, PC: 0, CFA: 0}
330 331 332 333 334 335 336 337 338 339 340 341

	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 {
342
			return scope.extractVariableFromEntry(entry)
343 344 345 346 347 348
		}
	}

	return nil, fmt.Errorf("could not find symbol value for %s", name)
}

349 350
func (scope *EvalScope) evaluateStructMember(parentEntry *dwarf.Entry, rdr *reader.Reader, memberName string) (*Variable, error) {
	parentAddr, err := scope.extractVariableDataAddress(parentEntry, rdr)
351 352 353
	if err != nil {
		return nil, err
	}
354

D
Derek Parker 已提交
355
	// Get parent variable name
356
	parentName, ok := parentEntry.Val(dwarf.AttrName).(string)
357
	if !ok {
D
Derek Parker 已提交
358
		return nil, fmt.Errorf("unable to retrive variable name")
359
	}
360 361

	// Seek reader to the type information so members can be iterated
362
	_, err = rdr.SeekToType(parentEntry, true, true)
363 364 365
	if err != nil {
		return nil, err
	}
366 367

	// Iterate to find member by name
368
	for memberEntry, err := rdr.NextMemberVariable(); memberEntry != nil; memberEntry, err = rdr.NextMemberVariable() {
369 370 371 372 373 374 375 376 377 378
		if err != nil {
			return nil, err
		}

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

		if name == memberName {
D
Derek Parker 已提交
379
			// Nil ptr, wait until here to throw a nil pointer error to prioritize no such member error
380 381 382 383
			if parentAddr == 0 {
				return nil, fmt.Errorf("%s is nil", parentName)
			}

384
			memberInstr, err := rdr.InstructionsForEntry(memberEntry)
385 386 387 388 389 390
			if err != nil {
				return nil, err
			}

			offset, ok := memberEntry.Val(dwarf.AttrType).(dwarf.Offset)
			if !ok {
D
Derek Parker 已提交
391
				return nil, fmt.Errorf("type assertion failed")
392 393
			}

394
			t, err := scope.Type(offset)
395 396 397 398
			if err != nil {
				return nil, err
			}

399 400 401 402
			baseAddr := make([]byte, 8)
			binary.LittleEndian.PutUint64(baseAddr, uint64(parentAddr))

			parentInstructions := append([]byte{op.DW_OP_addr}, baseAddr...)
403
			val, err := scope.extractValue(append(parentInstructions, memberInstr...), 0, t, true)
404 405 406 407 408 409 410
			if err != nil {
				return nil, err
			}
			return &Variable{Name: strings.Join([]string{parentName, memberName}, "."), Type: t.String(), Value: val}, nil
		}
	}

411
	return nil, fmt.Errorf("%s has no member %s", parentName, memberName)
412 413
}

E
epipho 已提交
414
// Extracts the name, type, and value of a variable from a dwarf entry
415
func (scope *EvalScope) extractVariableFromEntry(entry *dwarf.Entry) (*Variable, error) {
E
epipho 已提交
416
	if entry == nil {
D
Derek Parker 已提交
417
		return nil, fmt.Errorf("invalid entry")
E
epipho 已提交
418 419 420 421 422 423 424 425
	}

	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 已提交
426
		return nil, fmt.Errorf("type assertion failed")
E
epipho 已提交
427 428 429 430
	}

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

434
	t, err := scope.Type(offset)
E
epipho 已提交
435 436 437 438 439 440
	if err != nil {
		return nil, err
	}

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

444
	val, err := scope.extractValue(instructions, 0, t, true)
E
epipho 已提交
445 446 447 448 449 450 451
	if err != nil {
		return nil, err
	}

	return &Variable{Name: n, Type: t.String(), Value: val}, nil
}

452
// Extracts the address of a variable, dereferencing any pointers
453
func (scope *EvalScope) extractVariableDataAddress(entry *dwarf.Entry, rdr *reader.Reader) (int64, error) {
454
	instructions, err := rdr.InstructionsForEntry(entry)
455 456 457 458
	if err != nil {
		return 0, err
	}

459
	address, err := op.ExecuteStackProgram(scope.CFA, instructions)
460 461 462 463
	if err != nil {
		return 0, err
	}

D
Derek Parker 已提交
464
	// Dereference pointers to get down the concrete type
465
	for typeEntry, err := rdr.SeekToType(entry, true, false); typeEntry != nil; typeEntry, err = rdr.SeekToType(typeEntry, true, false) {
466
		if err != nil {
467
			return 0, err
468 469
		}

470 471 472 473 474 475
		if typeEntry.Tag != dwarf.TagPointerType {
			break
		}

		ptraddress := uintptr(address)

476
		ptr, err := scope.Thread.readMemory(ptraddress, scope.PtrSize())
477
		if err != nil {
478
			return 0, err
479
		}
480 481
		address = int64(binary.LittleEndian.Uint64(ptr))
	}
482

483 484
	return address, nil
}
485

486 487 488
// Extracts the value from the instructions given in the DW_AT_location entry.
// We execute the stack program described in the DW_OP_* instruction stream, and
// then grab the value from the other processes memory.
489 490
func (scope *EvalScope) extractValue(instructions []byte, addr int64, typ interface{}, printStructName bool) (string, error) {
	return scope.extractValueInternal(instructions, addr, typ, printStructName, 0)
491 492
}

493
func (scope *EvalScope) extractValueInternal(instructions []byte, addr int64, typ interface{}, printStructName bool, recurseLevel int) (string, error) {
494 495 496
	var err error

	if addr == 0 {
497
		addr, err = op.ExecuteStackProgram(scope.CFA, instructions)
498 499 500 501 502 503 504
		if err != nil {
			return "", err
		}
	}

	// If we have a user defined type, find the
	// underlying concrete type and use that.
505 506 507 508 509 510
	for {
		if tt, ok := typ.(*dwarf.TypedefType); ok {
			typ = tt.Type
		} else {
			break
		}
511 512
	}

513
	ptraddress := uintptr(addr)
514 515
	switch t := typ.(type) {
	case *dwarf.PtrType:
516
		ptr, err := scope.Thread.readMemory(ptraddress, scope.PtrSize())
517 518 519
		if err != nil {
			return "", err
		}
520 521 522 523 524 525

		intaddr := int64(binary.LittleEndian.Uint64(ptr))
		if intaddr == 0 {
			return fmt.Sprintf("%s nil", t.String()), nil
		}

526
		// Don't increase the recursion level when dereferencing pointers
527
		val, err := scope.extractValueInternal(nil, intaddr, t.Type, printStructName, recurseLevel)
528 529 530 531
		if err != nil {
			return "", err
		}

532
		return fmt.Sprintf("*%s", val), nil
533
	case *dwarf.StructType:
E
epipho 已提交
534 535
		switch {
		case t.StructName == "string":
536
			return scope.Thread.readString(ptraddress)
E
epipho 已提交
537
		case strings.HasPrefix(t.StructName, "[]"):
538
			return scope.readSlice(ptraddress, t, recurseLevel)
539
		default:
D
Derek Parker 已提交
540
			// Recursively call extractValue to grab
541
			// the value of all the members of the struct.
542 543 544
			if recurseLevel <= maxVariableRecurse {
				fields := make([]string, 0, len(t.Field))
				for _, field := range t.Field {
545
					val, err := scope.extractValueInternal(nil, field.ByteOffset+addr, field.Type, printStructName, recurseLevel+1)
546 547 548 549 550
					if err != nil {
						return "", err
					}

					fields = append(fields, fmt.Sprintf("%s: %s", field.Name, val))
551
				}
552 553 554 555
				if printStructName {
					return fmt.Sprintf("%s {%s}", t.StructName, strings.Join(fields, ", ")), nil
				}
				return fmt.Sprintf("{%s}", strings.Join(fields, ", ")), nil
556
			}
557
			// no fields
E
epipho 已提交
558
			if printStructName {
559
				return fmt.Sprintf("%s {...}", t.StructName), nil
E
epipho 已提交
560
			}
561
			return "{...}", nil
562 563
		}
	case *dwarf.ArrayType:
564
		return scope.readArray(ptraddress, t, recurseLevel)
565
	case *dwarf.ComplexType:
566
		return scope.Thread.readComplex(ptraddress, t.ByteSize)
567
	case *dwarf.IntType:
568
		return scope.Thread.readInt(ptraddress, t.ByteSize)
E
epipho 已提交
569
	case *dwarf.UintType:
570
		return scope.Thread.readUint(ptraddress, t.ByteSize)
571
	case *dwarf.FloatType:
572
		return scope.Thread.readFloat(ptraddress, t.ByteSize)
E
epipho 已提交
573
	case *dwarf.BoolType:
574
		return scope.Thread.readBool(ptraddress)
575
	case *dwarf.FuncType:
576
		return scope.Thread.readFunctionPtr(ptraddress)
577 578 579 580
	case *dwarf.VoidType:
		return "(void)", nil
	case *dwarf.UnspecifiedType:
		return "(unknown)", nil
581 582
	default:
		fmt.Printf("Unknown type: %T\n", t)
583 584 585 586 587
	}

	return "", fmt.Errorf("could not find value for type %s", typ)
}

D
Derek Parker 已提交
588
func (thread *Thread) readString(addr uintptr) (string, error) {
589 590 591 592
	// string data structure is always two ptrs in size. Addr, followed by len
	// http://research.swtch.com/godata

	// read len
593
	val, err := thread.readMemory(addr+uintptr(thread.dbp.arch.PtrSize()), thread.dbp.arch.PtrSize())
594
	if err != nil {
595
		return "", fmt.Errorf("could not read string len %s", err)
596
	}
597
	strlen := int(binary.LittleEndian.Uint64(val))
598 599

	// read addr
600
	val, err = thread.readMemory(addr, thread.dbp.arch.PtrSize())
601
	if err != nil {
602
		return "", fmt.Errorf("could not read string pointer %s", err)
603 604
	}
	addr = uintptr(binary.LittleEndian.Uint64(val))
D
Derek Parker 已提交
605 606 607
	if addr == 0 {
		return "", nil
	}
D
Derek Parker 已提交
608

609
	val, err = thread.readMemory(addr, strlen)
610
	if err != nil {
611
		return "", fmt.Errorf("could not read string at %#v due to %s", addr, err)
612 613
	}

D
Derek Parker 已提交
614
	return *(*string)(unsafe.Pointer(&val)), nil
615 616
}

617
func (scope *EvalScope) readSlice(addr uintptr, t *dwarf.StructType, recurseLevel int) (string, error) {
E
epipho 已提交
618 619 620 621 622 623
	var sliceLen, sliceCap int64
	var arrayAddr uintptr
	var arrayType dwarf.Type
	for _, f := range t.Field {
		switch f.Name {
		case "array":
624
			val, err := scope.Thread.readMemory(addr+uintptr(f.ByteOffset), scope.PtrSize())
E
epipho 已提交
625 626 627 628 629 630 631 632 633 634 635
			if err != nil {
				return "", err
			}
			arrayAddr = uintptr(binary.LittleEndian.Uint64(val))
			// 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)
			}
			arrayType = ptrType.Type
		case "len":
636
			lstr, err := scope.extractValue(nil, int64(addr+uintptr(f.ByteOffset)), f.Type, true)
E
epipho 已提交
637 638 639 640 641 642 643 644
			if err != nil {
				return "", err
			}
			sliceLen, err = strconv.ParseInt(lstr, 10, 64)
			if err != nil {
				return "", err
			}
		case "cap":
645
			cstr, err := scope.extractValue(nil, int64(addr+uintptr(f.ByteOffset)), f.Type, true)
E
epipho 已提交
646 647 648 649 650 651 652 653 654 655 656 657
			if err != nil {
				return "", err
			}
			sliceCap, err = strconv.ParseInt(cstr, 10, 64)
			if err != nil {
				return "", err
			}
		}
	}

	stride := arrayType.Size()
	if _, ok := arrayType.(*dwarf.PtrType); ok {
658
		stride = int64(scope.PtrSize())
E
epipho 已提交
659
	}
660
	vals, err := scope.readArrayValues(arrayAddr, sliceLen, stride, arrayType, recurseLevel)
661 662 663 664
	if err != nil {
		return "", err
	}

E
epipho 已提交
665 666
	return fmt.Sprintf("[]%s len: %d, cap: %d, [%s]", arrayType, sliceLen, sliceCap, strings.Join(vals, ",")), nil
}
667

668
func (scope *EvalScope) readArray(addr uintptr, t *dwarf.ArrayType, recurseLevel int) (string, error) {
669
	if t.Count > 0 {
670
		vals, err := scope.readArrayValues(addr, t.Count, t.ByteSize/t.Count, t.Type, recurseLevel)
671 672 673 674
		if err != nil {
			return "", err
		}
		return fmt.Sprintf("%s [%s]", t, strings.Join(vals, ",")), nil
675
	}
676 677
	// because you can declare a zero-size array
	return fmt.Sprintf("%s []", t), nil
678 679
}

680
func (scope *EvalScope) readArrayValues(addr uintptr, count int64, stride int64, t dwarf.Type, recurseLevel int) ([]string, error) {
E
epipho 已提交
681
	vals := make([]string, 0)
682

E
epipho 已提交
683
	for i := int64(0); i < count; i++ {
684 685 686 687 688 689
		// Cap number of elements
		if i >= maxArrayValues {
			vals = append(vals, fmt.Sprintf("...+%d more", count-maxArrayValues))
			break
		}

690
		val, err := scope.extractValueInternal(nil, int64(addr+uintptr(i*stride)), t, false, recurseLevel+1)
E
epipho 已提交
691
		if err != nil {
E
epipho 已提交
692
			return nil, err
E
epipho 已提交
693 694
		}
		vals = append(vals, val)
695
	}
E
epipho 已提交
696
	return vals, nil
697 698
}

699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
func (thread *Thread) readComplex(addr uintptr, size int64) (string, error) {
	var fs int64
	switch size {
	case 8:
		fs = 4
	case 16:
		fs = 8
	default:
		return "", fmt.Errorf("invalid size (%d) for complex type", size)
	}
	r, err := thread.readFloat(addr, fs)
	if err != nil {
		return "", err
	}
	i, err := thread.readFloat(addr+uintptr(fs), fs)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("(%s, %si)", r, i), nil
}

D
Derek Parker 已提交
720
func (thread *Thread) readInt(addr uintptr, size int64) (string, error) {
D
Derek Parker 已提交
721 722 723 724 725 726 727
	n, err := thread.readIntRaw(addr, size)
	if err != nil {
		return "", err
	}
	return strconv.FormatInt(n, 10), nil
}

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

731
	val, err := thread.readMemory(addr, int(size))
732
	if err != nil {
D
Derek Parker 已提交
733
		return 0, err
734 735
	}

736 737
	switch size {
	case 1:
E
epipho 已提交
738
		n = int64(val[0])
739
	case 2:
E
epipho 已提交
740
		n = int64(binary.LittleEndian.Uint16(val))
741
	case 4:
E
epipho 已提交
742
		n = int64(binary.LittleEndian.Uint32(val))
743
	case 8:
E
epipho 已提交
744
		n = int64(binary.LittleEndian.Uint64(val))
745
	}
746

D
Derek Parker 已提交
747
	return n, nil
E
epipho 已提交
748 749
}

D
Derek Parker 已提交
750
func (thread *Thread) readUint(addr uintptr, size int64) (string, error) {
D
Derek Parker 已提交
751 752 753 754 755 756 757
	n, err := thread.readUintRaw(addr, size)
	if err != nil {
		return "", err
	}
	return strconv.FormatUint(n, 10), nil
}

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

761
	val, err := thread.readMemory(addr, int(size))
E
epipho 已提交
762
	if err != nil {
D
Derek Parker 已提交
763
		return 0, err
E
epipho 已提交
764 765 766 767 768 769 770 771 772 773 774 775 776
	}

	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 已提交
777
	return n, nil
778 779
}

D
Derek Parker 已提交
780
func (thread *Thread) readFloat(addr uintptr, size int64) (string, error) {
781
	val, err := thread.readMemory(addr, int(size))
782 783 784 785 786
	if err != nil {
		return "", err
	}
	buf := bytes.NewBuffer(val)

D
Derek Parker 已提交
787 788 789 790 791 792 793 794 795 796 797
	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 已提交
798
	return "", fmt.Errorf("could not read float")
799 800
}

D
Derek Parker 已提交
801
func (thread *Thread) readBool(addr uintptr) (string, error) {
802
	val, err := thread.readMemory(addr, 1)
E
epipho 已提交
803 804 805 806 807 808 809 810 811 812 813
	if err != nil {
		return "", err
	}

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

	return "true", nil
}

D
Derek Parker 已提交
814
func (thread *Thread) readFunctionPtr(addr uintptr) (string, error) {
815
	val, err := thread.readMemory(addr, thread.dbp.arch.PtrSize())
816 817 818 819 820 821
	if err != nil {
		return "", err
	}

	// dereference pointer to find function pc
	addr = uintptr(binary.LittleEndian.Uint64(val))
822 823 824
	if addr == 0 {
		return "nil", nil
	}
825

826
	val, err = thread.readMemory(addr, thread.dbp.arch.PtrSize())
827 828 829 830 831
	if err != nil {
		return "", err
	}

	funcAddr := binary.LittleEndian.Uint64(val)
832
	fn := thread.dbp.goSymTable.PCToFunc(uint64(funcAddr))
833 834
	if fn == nil {
		return "", fmt.Errorf("could not find function for %#v", funcAddr)
835 836
	}

837
	return fn.Name, nil
838 839
}

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

844
	_, err := reader.SeekToFunction(scope.PC)
845
	if err != nil {
E
epipho 已提交
846 847 848 849 850
		return nil, err
	}

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

851
	for entry, err := reader.NextScopeVariable(); entry != nil; entry, err = reader.NextScopeVariable() {
E
epipho 已提交
852 853 854 855 856
		if err != nil {
			return nil, err
		}

		if entry.Tag == tag {
857
			val, err := scope.extractVariableFromEntry(entry)
E
epipho 已提交
858
			if err != nil {
E
epipho 已提交
859 860
				// skip variables that we can't parse yet
				continue
E
epipho 已提交
861 862 863 864 865 866 867 868
			}

			vars = append(vars, val)
		}
	}

	return vars, nil
}