internal/gocore: extract type name of method value from its wrapper function name

It's a single-entry closure laid out like `{pc uintptr, x T}`, and the target pc is for wrapper functions named like pkg.T.m-fm or pkg.(*T).m-fm.
So, extract the type name pkg.T or *pkg.T from its wrapper function name.

Change-Id: I2b5a2db60ee4d875cd0b9ffb3c4f21a69eef0459
GitHub-Last-Rev: 06c4fafc0dcb54bed351ff2f208238d4a43decad
GitHub-Pull-Request: golang/debug#13
Reviewed-on: https://go-review.googlesource.com/c/debug/+/419179
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/internal/gocore/type.go b/internal/gocore/type.go
index 05d15b9..5a944c7 100644
--- a/internal/gocore/type.go
+++ b/internal/gocore/type.go
@@ -6,6 +6,7 @@
 
 import (
 	"fmt"
+	"regexp"
 	"strings"
 
 	"golang.org/x/debug/internal/core"
@@ -545,6 +546,29 @@
 	return fr.p.proc.ReadInt(a)
 }
 
+// Match wrapper function name for method value.
+// eg. main.(*Bar).func-fm, or main.Bar.func-fm.
+var methodRegexp = regexp.MustCompile(`(\w+)\.(\(\*)?(\w+)(\))?\.\w+\-fm$`)
+
+// Extract the type of the method value from its wrapper function name,
+// return the type named *main.Bar or main.Bar, in the previous cases.
+func extractTypeFromFunctionName(method string, p *Process) *Type {
+	if matches := methodRegexp.FindStringSubmatch(method); len(matches) == 5 {
+		var typeName string
+		if matches[2] == "(*" && matches[4] == ")" {
+			typeName = "*" + matches[1] + "." + matches[3]
+		} else {
+			typeName = matches[1] + "." + matches[3]
+		}
+		s := p.runtimeNameMap[typeName]
+		if len(s) > 0 {
+			// TODO: filter with the object size when there are multiple candidates.
+			return s[0]
+		}
+	}
+	return nil
+}
+
 // typeObject takes an address and a type for the data at that address.
 // For each pointer it finds in the memory at that address, it calls add with the pointer
 // and the type + repeat count of the thing that it points to.
@@ -635,6 +659,12 @@
 			f.closure = ft
 		}
 		p.typeObject(closure, ft, r, add)
+		// handle the special case for method value.
+		// It's a single-entry closure laid out like {pc uintptr, x T}.
+		if typ := extractTypeFromFunctionName(f.name, p); typ != nil {
+			ptr := closure.Add(p.proc.PtrSize())
+			p.typeObject(ptr, typ, r, add)
+		}
 	case KindArray:
 		n := t.Elem.Size
 		for i := int64(0); i < t.Count; i++ {