gocore: add function to find the dynamic type of an interface

Typically you could also get this type from following the data
pointer of the interface. But the direct vs indirect distinction
means you can't distinguish between *T and T, and for typed nils
there's no way to find the type.

Instead, just provide this functionality directly.

Change-Id: I70d1a613b815c4ffe93dea9ada73c0b065907b78
Reviewed-on: https://go-review.googlesource.com/92415
Reviewed-by: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
diff --git a/gocore/gocore_test.go b/gocore/gocore_test.go
index ab6d980..320bac9 100644
--- a/gocore/gocore_test.go
+++ b/gocore/gocore_test.go
@@ -163,3 +163,15 @@
 		t.Errorf("forward and reverse edges don't match")
 	}
 }
+
+func TestDynamicType(t *testing.T) {
+	p := loadExample(t)
+	for _, g := range p.Globals() {
+		if g.Name == "runtime.indexError" {
+			d := p.DynamicType(g.Type, g.Addr)
+			if d.Name != "runtime.errorString" {
+				t.Errorf("dynamic type wrong: got %s want runtime.errorString", d.Name)
+			}
+		}
+	}
+}
diff --git a/gocore/type.go b/gocore/type.go
index 17c9c57..08b5cd1 100644
--- a/gocore/type.go
+++ b/gocore/type.go
@@ -87,6 +87,29 @@
 	return nil
 }
 
+// DynamicType returns the concrete type stored in the interface type t at address a.
+// If the interface is nil, returns nil.
+func (p *Process) DynamicType(t *Type, a core.Address) *Type {
+	switch t.Kind {
+	default:
+		panic("asking for the dynamic type of a non-interface")
+	case KindEface:
+		x := p.proc.ReadPtr(a)
+		if x == 0 {
+			return nil
+		}
+		return p.runtimeType2Type(x)
+	case KindIface:
+		x := p.proc.ReadPtr(a)
+		if x == 0 {
+			return nil
+		}
+		// Read type out of itab.
+		x = p.proc.ReadPtr(x.Add(p.proc.PtrSize()))
+		return p.runtimeType2Type(x)
+	}
+}
+
 // Convert the address of a runtime._type to a *Type.
 // Guaranteed to return a non-nil *Type.
 func (p *Process) runtimeType2Type(a core.Address) *Type {
@@ -122,7 +145,7 @@
 		// A reflect-generated type.
 		// TODO: The actual name is in the runtime.reflectOffs map.
 		// Too hard to look things up in maps here, just allocate a placeholder for now.
-		name = fmt.Sprintf("reflect.generated%x", a)
+		name = fmt.Sprintf("reflect.generatedType%x", a)
 	}
 
 	// Read ptr/nonptr bits