in cmd/viewcore/main.go [619:701]
func runReachable(cmd *cobra.Command, args []string) {
_, c, err := readCore()
if err != nil {
exitf("%v\n", err)
}
n, err := strconv.ParseInt(args[0], 16, 64)
if err != nil {
exitf("can't parse %q as an object address\n", args[1])
}
a := core.Address(n)
obj, _ := c.FindObject(a)
if obj == 0 {
exitf("can't find object at address %s\n", args[1])
}
// Breadth-first search backwards until we reach a root.
type hop struct {
i int64 // offset in "from" object (the key in the path map) where the pointer is
x gocore.Object // the "to" object
j int64 // the offset in the "to" object
}
depth := map[gocore.Object]int{}
depth[obj] = 0
q := []gocore.Object{obj}
done := false
for !done {
if len(q) == 0 {
panic("can't find a root that can reach the object")
}
y := q[0]
q = q[1:]
c.ForEachReversePtr(y, func(x gocore.Object, r *gocore.Root, i, j int64) bool {
if r != nil {
// found it.
if r.Frame == nil {
// Print global
fmt.Printf("%s", r.Name)
} else {
// Print stack up to frame in question.
var frames []*gocore.Frame
for f := r.Frame.Parent(); f != nil; f = f.Parent() {
frames = append(frames, f)
}
for k := len(frames) - 1; k >= 0; k-- {
fmt.Printf("%s\n", frames[k].Func().Name())
}
// Print frame + variable in frame.
fmt.Printf("%s.%s", r.Frame.Func().Name(), r.Name)
}
fmt.Printf("%s → \n", typeFieldName(r.Type, i))
z := y
for {
fmt.Printf("%x %s", c.Addr(z), typeName(c, z))
if z == obj {
fmt.Println()
break
}
// Find an edge out of z which goes to an object
// closer to obj.
c.ForEachPtr(z, func(i int64, w gocore.Object, j int64) bool {
if d, ok := depth[w]; ok && d < depth[z] {
fmt.Printf(" %s → %s", objField(c, z, i), objRegion(c, w, j))
z = w
return false
}
return true
})
fmt.Println()
}
done = true
return false
}
if _, ok := depth[x]; ok {
// we already found a shorter path to this object.
return true
}
depth[x] = depth[y] + 1
q = append(q, x)
return true
})
}
}