From 60e1cf4d4d6f700fd9c4847be15c79a870652b9d Mon Sep 17 00:00:00 2001 From: Stephen Eckels Date: Mon, 9 Oct 2023 13:35:29 -0400 Subject: [PATCH] Add interface method name recovery --- main.go | 1 + main_test.go | 31 +++++++++++++++++++++++++++++++ objfile/objfile.go | 23 ++++++++++++++++++----- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 033c870..e2003cc 100644 --- a/main.go +++ b/main.go @@ -268,6 +268,7 @@ restartParseWithRealTextBase: extractMetadata.Types = types } + // the ITabLinks did not always exist, older versions it will be NULL interfaces, err := file.ParseITabLinks(extractMetadata.Version, moduleData, extractMetadata.TabMeta.PointerSize == 8, extractMetadata.TabMeta.Endianess == "LittleEndian") if err == nil { extractMetadata.Interfaces = interfaces diff --git a/main_test.go b/main_test.go index f80bd56..0878db6 100644 --- a/main_test.go +++ b/main_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "os" + "strings" "testing" _ "net/http/pprof" @@ -53,6 +54,36 @@ func TestAllVersions(t *testing.T) { } } + if v != "15" && v != "16" { + found_interface := false + for _, typ := range data.Types { + if typ.Str == "io.Writer" && typ.Kind == "Interface" { + found_interface = true + if !strings.Contains(typ.Reconstructed, "Write([]uint8) (int, error)") { + t.Errorf("Go %s interface method name recovery failed", v) + } + } + } + + if !found_interface { + t.Errorf("Go %s interface recovery failed", v) + } + } else { + found_interface := false + for _, typ := range data.Types { + if typ.Str == "os.FileInfo" && typ.Kind == "Interface" { + found_interface = true + if !strings.Contains(typ.Reconstructed, "IsDir() bool") { + t.Errorf("Go %s interface method name recovery failed", v) + } + } + } + + if !found_interface { + t.Errorf("Go %s interface recovery failed", v) + } + } + if len(data.StdFunctions) == 0 { t.Errorf("Go %s std functions failed on %s: %s", v, file, err) } diff --git a/objfile/objfile.go b/objfile/objfile.go index 4541f28..44b728f 100644 --- a/objfile/objfile.go +++ b/objfile/objfile.go @@ -1447,10 +1447,17 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty typeAddr := decodePtrSizeBytes(imethoddata[ptrSize*2:ptrSize*3], is64bit, littleendian) parsedTypesIn, _ = e.ParseType_impl(runtimeVersion, moduleData, typeAddr, is64bit, littleendian, parsedTypesIn) + + name_ptr := decodePtrSizeBytes(imethoddata[0:ptrSize], is64bit, littleendian) + name, err := e.readRTypeName(runtimeVersion, 0, name_ptr, is64bit, littleendian) + if err != nil { + continue + } + methodfunc, found := parsedTypesIn.Get(typeAddr) if found { - interfaceDef += "\nmethod" + strconv.Itoa(i) + " " + methodfunc.(Type).Str - cinterfaceDef += methodfunc.(Type).CStr + "method" + strconv.Itoa(i) + ";\n" + interfaceDef += strings.Replace(methodfunc.(Type).Str, "func", name, 1) + "\n" + cinterfaceDef += methodfunc.(Type).CStr + " " + name + ";\n" } } interfaceDef += "\n}" @@ -1513,7 +1520,7 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty interfaceDef := "type interface {" cinterfaceDef := "struct interface {\n" (*_type).CStr = "interface_" - if *&_type.flags&tflagNamed != 0 { + if _type.flags&tflagNamed != 0 { interfaceDef = fmt.Sprintf("type %s interface {", _type.Str) cinterfaceDef = fmt.Sprintf("struct %s_interface {\n", _type.CStr) (*_type).CStr = fmt.Sprintf("%s_interface", _type.CStr) @@ -1539,10 +1546,16 @@ func (e *Entry) ParseType_impl(runtimeVersion string, moduleData *ModuleData, ty typeAddr := moduleData.Types + uint64(method.Typ) parsedTypesIn, _ = e.ParseType_impl(runtimeVersion, moduleData, typeAddr, is64bit, littleendian, parsedTypesIn) + name_ptr := moduleData.Types + uint64(method.Name) + name, err := e.readRTypeName(runtimeVersion, 0, name_ptr, is64bit, littleendian) + if err != nil { + continue + } + methodfunc, found := parsedTypesIn.Get(typeAddr) if found { - interfaceDef += "\nmethod" + strconv.Itoa(i) + " " + methodfunc.(Type).Str - cinterfaceDef += methodfunc.(Type).CStr + " method" + strconv.Itoa(i) + ";\n" + interfaceDef += strings.Replace(methodfunc.(Type).Str, "func", name, 1) + "\n" + cinterfaceDef += methodfunc.(Type).CStr + " " + name + ";\n" } } interfaceDef += "\n}"