func()

in internal/gocore/dwarf.go [462:604]


func (p *Process) readStackVars() {
	type Var struct {
		name string
		off  int64
		typ  *Type
	}
	vars := map[*Func][]Var{}
	var curfn *Func
	d, _ := p.proc.DWARF()
	r := d.Reader()
	for e, err := r.Next(); e != nil && err == nil; e, err = r.Next() {
		if isNonGoCU(e) {
			r.SkipChildren()
			continue
		}

		if e.Tag == dwarf.TagSubprogram {
			lowpc := e.AttrField(dwarf.AttrLowpc)
			highpc := e.AttrField(dwarf.AttrHighpc)
			if lowpc == nil || highpc == nil {
				continue
			}
			min := core.Address(lowpc.Val.(uint64))
			max := core.Address(highpc.Val.(uint64))
			f := p.funcTab.find(min)
			if f == nil {
				// some func Go doesn't know about. C?
				curfn = nil
			} else {
				if f.entry != min {
					panic("dwarf and runtime don't agree about start of " + f.name)
				}
				if p.funcTab.find(max-1) != f {
					panic("function ranges don't match for " + f.name)
				}
				curfn = f
			}
			continue
		}
		if e.Tag != dwarf.TagVariable && e.Tag != dwarf.TagFormalParameter {
			continue
		}
		aloc := e.AttrField(dwarf.AttrLocation)
		if aloc == nil {
			continue
		}
		if aloc.Class != dwarf.ClassExprLoc {
			// TODO: handle ClassLocListPtr here.
			// As of go 1.11, locals are encoded this way.
			// Until we fix this TODO, viewcore will not be able to
			// show local variables.
			continue
		}
		// Interpret locations of the form
		//    DW_OP_call_frame_cfa
		//    DW_OP_consts <off>
		//    DW_OP_plus
		// (with possibly missing DW_OP_consts & DW_OP_plus for the zero offset.)
		// TODO: handle other possible locations (e.g. register locations).
		loc := aloc.Val.([]byte)
		if len(loc) == 0 || loc[0] != _DW_OP_call_frame_cfa {
			continue
		}
		loc = loc[1:]
		var off int64
		if len(loc) != 0 && loc[0] == _DW_OP_consts {
			loc = loc[1:]
			var s uint
			for len(loc) > 0 {
				b := loc[0]
				loc = loc[1:]
				off += int64(b&0x7f) << s
				s += 7
				if b&0x80 == 0 {
					break
				}
			}
			off = off << (64 - s) >> (64 - s)
			if len(loc) == 0 || loc[0] != _DW_OP_plus {
				continue
			}
			loc = loc[1:]
		}
		if len(loc) != 0 {
			continue // more stuff we don't recognize
		}
		f := e.AttrField(dwarf.AttrType)
		if f == nil {
			continue
		}
		dt, err := d.Type(f.Val.(dwarf.Offset))
		if err != nil {
			panic(err)
		}
		nf := e.AttrField(dwarf.AttrName)
		if nf == nil {
			continue
		}
		name := nf.Val.(string)
		vars[curfn] = append(vars[curfn], Var{name: name, off: off, typ: p.dwarfMap[dt]})
	}

	// Get roots from goroutine stacks.
	for _, g := range p.goroutines {
		for _, f := range g.frames {
			// Start with all pointer slots as unnamed.
			unnamed := map[core.Address]bool{}
			for a := range f.Live {
				unnamed[a] = true
			}
			// Emit roots for DWARF entries.
			for _, v := range vars[f.f] {
				r := &Root{
					Name:  v.name,
					Addr:  f.max.Add(v.off),
					Type:  v.typ,
					Frame: f,
				}
				f.roots = append(f.roots, r)
				// Remove this variable from the set of unnamed pointers.
				for a := r.Addr; a < r.Addr.Add(r.Type.Size); a = a.Add(p.proc.PtrSize()) {
					delete(unnamed, a)
				}
			}
			// Emit roots for unnamed pointer slots in the frame.
			// Make deterministic by sorting first.
			s := make([]core.Address, 0, len(unnamed))
			for a := range unnamed {
				s = append(s, a)
			}
			sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
			for _, a := range s {
				r := &Root{
					Name:  "unk",
					Addr:  a,
					Type:  p.findType("unsafe.Pointer"),
					Frame: f,
				}
				f.roots = append(f.roots, r)
			}
		}
	}
}