diff --git a/elf.go b/elf.go index 69577d0..b0ed3a4 100644 --- a/elf.go +++ b/elf.go @@ -20,7 +20,6 @@ package gore import ( "debug/dwarf" "debug/elf" - "debug/gosym" "errors" "fmt" "os" @@ -36,7 +35,12 @@ func openELF(fp string) (*elfFile, error) { if err != nil { return nil, fmt.Errorf("error when parsing the ELF file: %w", err) } - return &elfFile{file: f, osFile: osFile}, nil + return &elfFile{ + file: f, + osFile: osFile, + pcln: newPclnTabOnce(), + symtab: newSymbolTableOnce(), + }, nil } var _ fileHandler = (*elfFile)(nil) @@ -44,6 +48,49 @@ var _ fileHandler = (*elfFile)(nil) type elfFile struct { file *elf.File osFile *os.File + pcln *pclntabOnce + symtab *symbolTableOnce +} + +func (e *elfFile) initSymTab() error { + e.symtab.Do(func() { + syms, err := e.file.Symbols() + if err != nil { + // If the error is ErrNoSymbols, we just ignore it. + if !errors.Is(err, elf.ErrNoSymbols) { + e.symtab.err = fmt.Errorf("error when getting the symbols: %w", err) + } + return + } + for _, sym := range syms { + e.symtab.table[sym.Name] = symbol{ + Name: sym.Name, + Value: sym.Value, + Size: sym.Size, + } + } + }) + return e.symtab.err +} + +func (e *elfFile) hasSymbolTable() (bool, error) { + err := e.initSymTab() + if err != nil { + return false, err + } + return len(e.symtab.table) > 0, nil +} + +func (e *elfFile) getSymbol(name string) (uint64, uint64, error) { + err := e.initSymTab() + if err != nil { + return 0, 0, err + } + sym, ok := e.symtab.table[name] + if !ok { + return 0, 0, ErrSymbolNotFound + } + return sym.Value, sym.Size, nil } func (e *elfFile) getParsedFile() any { @@ -54,23 +101,57 @@ func (e *elfFile) getFile() *os.File { return e.osFile } -func (e *elfFile) getPCLNTab() (*gosym.Table, error) { - pclnSection := e.file.Section(".gopclntab") - if pclnSection == nil { - // No section found. Check if the PIE section exist instead. - pclnSection = e.file.Section(".data.rel.ro.gopclntab") +func (e *elfFile) searchForPclnTab() (uint64, []byte, error) { + // Only use linkmode=external and buildmode=pie will lead to this + // Since the external linker merged all .data.rel.ro.* sections into .data.rel.ro + // So we have to find .data.rel.ro.gopclntab manually + sec := e.file.Section(".data.rel.ro") + if sec == nil { + return 0, nil, ErrNoPCLNTab } - if pclnSection == nil { - return nil, fmt.Errorf("no gopclntab section found") + data, err := sec.Data() + if err != nil { + return 0, nil, fmt.Errorf("could not get the data for the pclntab: %w", err) } - pclndat, err := pclnSection.Data() + tab, err := searchSectionForTab(data, e.getFileInfo().ByteOrder) if err != nil { - return nil, fmt.Errorf("could not get the data for the pclntab: %w", err) + return 0, nil, fmt.Errorf("could not find the pclntab: %w", err) } + addr := sec.Addr + sec.FileSize - uint64(len(tab)) + return addr, tab, nil +} - pcln := gosym.NewLineTable(pclndat, e.file.Section(".text").Addr) - return gosym.NewTable(make([]byte, 0), pcln) +func (e *elfFile) symbolData(start, end string) (uint64, uint64, []byte) { + elfSyms, err := e.file.Symbols() + if err != nil { + return 0, 0, nil + } + var addr, eaddr uint64 + for _, s := range elfSyms { + if s.Name == start { + addr = s.Value + } else if s.Name == end { + eaddr = s.Value + } + if addr != 0 && eaddr != 0 { + break + } + } + if addr == 0 || eaddr < addr { + return 0, 0, nil + } + size := eaddr - addr + data := make([]byte, size) + for _, prog := range e.file.Progs { + if prog.Vaddr <= addr && addr+size-1 <= prog.Vaddr+prog.Filesz-1 { + if _, err := prog.ReadAt(data, int64(addr-prog.Vaddr)); err != nil { + return 0, 0, nil + } + return addr, eaddr, data + } + } + return 0, 0, nil } func (e *elfFile) Close() error { @@ -101,13 +182,36 @@ func (e *elfFile) getCodeSection() (uint64, []byte, error) { return section.Addr, data, nil } -func (e *elfFile) getPCLNTABData() (uint64, []byte, error) { - start, data, err := e.getSectionData(".gopclntab") - if errors.Is(err, ErrSectionDoesNotExist) { - // Try PIE location - return e.getSectionData(".data.rel.ro.gopclntab") +func (e *elfFile) getPCLNTABData() (start uint64, data []byte, err error) { + return e.pcln.load(e.getPCLNTABDataImpl) +} + +func (e *elfFile) getPCLNTABDataImpl() (start uint64, data []byte, err error) { + pclnSection := e.file.Section(".gopclntab") + if pclnSection == nil { + // No section found. Check if the PIE section exists instead. + pclnSection = e.file.Section(".data.rel.ro.gopclntab") + } + if pclnSection != nil { + data, err = pclnSection.Data() + if err != nil { + return 0, nil, fmt.Errorf("could not get the data for the pclntab: %w", err) + } + return pclnSection.Addr, data, nil + } + + // try to get data from symbol + start, _, data = e.symbolData("runtime.pclntab", "runtime.epclntab") + if data != nil { + return start, data, nil + } + + // try brute force searching for the pclntab + start, data, err = e.searchForPclnTab() + if err != nil { + return 0, nil, fmt.Errorf("could not find the pclntab: %w", err) } - return start, data, err + return } func (e *elfFile) moduledataSection() string { diff --git a/file.go b/file.go index 4e31842..2244acb 100644 --- a/file.go +++ b/file.go @@ -140,11 +140,8 @@ type GoFile struct { func (f *GoFile) initModuleData() error { f.initModuleDataOnce.Do(func() { - err := f.ensureCompilerVersion() - if err != nil { - f.initModuleDataError = err - return - } + // since we can traverse moduledata now, no goversion no longer an unrecoverable error + _ = f.ensureCompilerVersion() f.moduledata, f.initModuleDataError = extractModuledata(f.FileInfo, f.fh) }) return f.initModuleDataError @@ -159,6 +156,10 @@ func (f *GoFile) Moduledata() (Moduledata, error) { return f.moduledata, nil } +// initPackages initializes the packages in the binary. +// Note: this init depends on the moduledata initialization internal since PCLNTab() is called. +// any further modifications to moduledata initialization should consider this +// or a cycle dependency will be created. func (f *GoFile) initPackages() error { f.initPackagesOnce.Do(func() { tab, err := f.PCLNTab() @@ -378,7 +379,16 @@ func (f *GoFile) Close() error { // PCLNTab returns the PCLN table. func (f *GoFile) PCLNTab() (*gosym.Table, error) { - return f.fh.getPCLNTab() + err := f.initModuleData() + if err != nil { + return nil, err + } + _, data, err := f.fh.getPCLNTABData() + if err != nil { + return nil, err + } + pcln := gosym.NewLineTable(data, f.moduledata.TextAddr) + return gosym.NewTable(make([]byte, 0), pcln) } // GetTypes returns a map of all types found in the binary file. @@ -436,13 +446,15 @@ func sortTypes(types map[uint64]*GoType) []*GoType { type fileHandler interface { io.Closer - getPCLNTab() (*gosym.Table, error) + // returns the size, value and error + getSymbol(name string) (uint64, uint64, error) + hasSymbolTable() (bool, error) + getPCLNTABData() (uint64, []byte, error) getRData() ([]byte, error) getCodeSection() (uint64, []byte, error) getSectionDataFromAddress(uint64) (uint64, []byte, error) getSectionData(string) (uint64, []byte, error) getFileInfo() *FileInfo - getPCLNTABData() (uint64, []byte, error) moduledataSection() string getBuildID() (string, error) getFile() *os.File diff --git a/file_test.go b/file_test.go index 3f1472f..11e67b6 100644 --- a/file_test.go +++ b/file_test.go @@ -20,7 +20,6 @@ package gore import ( "debug/dwarf" "debug/elf" - "debug/gosym" "debug/macho" "debug/pe" "errors" @@ -175,6 +174,15 @@ type mockFileHandler struct { mGetSectionDataFromAddress func(uint64) (uint64, []byte, error) } +func (m *mockFileHandler) hasSymbolTable() (bool, error) { + //TODO implement me + panic("implement me") +} + +func (m *mockFileHandler) getSymbol(name string) (uint64, uint64, error) { + panic("implement me") +} + func (m *mockFileHandler) getFile() *os.File { panic("not implemented") } @@ -187,10 +195,6 @@ func (m *mockFileHandler) Close() error { panic("not implemented") } -func (m *mockFileHandler) getPCLNTab() (*gosym.Table, error) { - panic("not implemented") -} - func (m *mockFileHandler) getRData() ([]byte, error) { panic("not implemented") } @@ -279,6 +283,11 @@ func getGoldenResources() ([]string, error) { const testresourcesrc = ` package main +import ( + "fmt" + "runtime" +) + //go:noinline func getData() string { return "Name: GoRE" @@ -287,18 +296,7 @@ func getData() string { func main() { data := getData() data += " | Test" -} -` - -const nostripSrc = ` -package main - -import ( - "fmt" - "runtime" -) - -func main() { fmt.Println(runtime.GOROOT()) + fmt.Println(data) } ` diff --git a/gen/gen.go b/gen/gen.go index a89fdd7..eaa1157 100644 --- a/gen/gen.go +++ b/gen/gen.go @@ -21,17 +21,21 @@ package main import ( + "flag" "fmt" - "os" ) +var forceUpdate = flag.Bool("force", false, "force update") + func main() { - if len(os.Args) != 2 { - fmt.Println("go run ./gen [stdpkgs|goversion|moduledata]") + flag.Parse() + + if flag.NArg() < 1 { + fmt.Println("go run ./gen [--force] [stdpkgs|goversion|moduledata]") return } - switch os.Args[1] { + switch flag.Arg(0) { case "stdpkgs": generateStdPkgs() case "goversion": diff --git a/gen/moduledata.go b/gen/moduledata.go index baed79d..fea95e5 100644 --- a/gen/moduledata.go +++ b/gen/moduledata.go @@ -19,6 +19,7 @@ package main import ( "bytes" + "cmp" "fmt" "github.com/go-git/go-git/v5/plumbing" "github.com/goretk/gore/extern" @@ -29,6 +30,7 @@ import ( "go/token" "os" "regexp" + "slices" "sort" "strconv" "strings" @@ -90,7 +92,6 @@ func getCurrentMaxGoBit() (int, error) { if typeSpec, ok := spec.(*ast.TypeSpec); ok { if _, ok := typeSpec.Type.(*ast.StructType); ok { name := typeSpec.Name.Name - if moduleNameMatcher.MatchString(name) { matches := moduleNameMatcher.FindStringSubmatch(name) if len(matches) != 2 { @@ -129,7 +130,7 @@ func getModuleDataSources() (map[int]string, error) { return nil, err } - if currentMaxMinor == maxMinor { + if currentMaxMinor == maxMinor && !*forceUpdate { return nil, nil } @@ -200,19 +201,39 @@ func (g *moduleDataGenerator) add(versionCode int, code string) error { } func (g *moduleDataGenerator) writeSelector() { - g.writeln("func selectModuleData(v int, bits int) (modulable,error) {") - g.writeln("switch {") + g.writefln("func selectModuleData(v int, bits int) (modulable,error) {") + g.writefln("switch {") for _, versionCode := range g.knownVersions { for _, bits := range []int{32, 64} { - g.writeln("case v == %d && bits == %d:", versionCode, bits) - g.writeln("return &%s{}, nil", g.generateTypeName(versionCode, bits)) + g.writefln("case v == %d && bits == %d:", versionCode, bits) + g.writefln("return &%s{}, nil", g.generateTypeName(versionCode, bits)) } } - g.writeln("default:") - g.writeln(`return nil, fmt.Errorf("unsupported version %%d and bits %%d", v, bits)`) + g.writefln("default:") + g.writeln(`return nil, fmt.Errorf("unsupported version %d and bits %d", v, bits)`) + + g.writefln("}\n}\n") +} - g.writeln("}\n}\n") +func (g *moduleDataGenerator) writeModuleListGetter() { + g.writefln("func getModuleDataList(bits int) ([]modulable, error) {") + g.writeln("if bits != 32 && bits != 64 { return nil, fmt.Errorf(\"unsupported bits %d\", bits)}") + + g.writefln("if bits == 32 {") + g.writefln("return []modulable{") + for _, versionCode := range g.knownVersions { + g.writefln("&%s{},", g.generateTypeName(versionCode, 32)) + } + g.writefln("}, nil") + g.writefln("} else {") + g.writefln("return []modulable{") + for _, versionCode := range g.knownVersions { + g.writefln("&%s{},", g.generateTypeName(versionCode, 64)) + } + g.writefln("}, nil") + g.writefln("}") + g.writefln("}\n") } @@ -227,12 +248,24 @@ func (*moduleDataGenerator) wrapValue(name string, bits int) string { return name } -func (*moduleDataGenerator) title(s string) string { - return strings.ToUpper(s[:1]) + s[1:] +func (g *moduleDataGenerator) writefln(format string, a ...interface{}) { + _, _ = fmt.Fprintf(g.buf, format+"\n", a...) } -func (g *moduleDataGenerator) writeln(format string, a ...interface{}) { - _, _ = fmt.Fprintf(g.buf, format+"\n", a...) +func (g *moduleDataGenerator) writef(format string, a ...interface{}) { + _, _ = fmt.Fprintf(g.buf, format, a...) +} + +func (g *moduleDataGenerator) writeln(s string) { + _, _ = g.buf.WriteString(s + "\n") +} + +func (g *moduleDataGenerator) write(s string) { + _, _ = g.buf.WriteString(s) +} + +func (*moduleDataGenerator) title(s string) string { + return strings.ToUpper(s[:1]) + s[1:] } func (g *moduleDataGenerator) writeVersionedModuleData(versionCode int, code string) error { @@ -246,7 +279,7 @@ func (g *moduleDataGenerator) writeVersionedModuleData(versionCode int, code str } writeCode := func(bits int) { - g.writeln("type %s struct {\n", g.generateTypeName(versionCode, bits)) + g.writefln("type %s struct {\n", g.generateTypeName(versionCode, bits)) knownFields := make(map[string]struct{}) search: @@ -266,17 +299,17 @@ func (g *moduleDataGenerator) writeVersionedModuleData(versionCode int, code str switch t := field.Type.(type) { case *ast.StarExpr: - g.writeln("%s uint%d", g.title(name.Name), bits) + g.writefln("%s uint%d", g.title(name.Name), bits) case *ast.ArrayType: - g.writeln("%s, %[1]slen, %[1]scap uint%d", g.title(name.Name), bits) + g.writefln("%s, %[1]slen, %[1]scap uint%d", g.title(name.Name), bits) case *ast.Ident: switch t.Name { case "uintptr": - g.writeln("%s uint%d", g.title(name.Name), bits) + g.writefln("%s uint%d", g.title(name.Name), bits) case "string": - g.writeln("%s, %[1]slen uint%d", g.title(name.Name), bits) + g.writefln("%s, %[1]slen uint%d", g.title(name.Name), bits) case "uint8": - g.writeln("%s uint8", g.title(name.Name)) + g.writefln("%s uint8", g.title(name.Name)) default: panic(fmt.Sprintf("unhandled type: %+v", t)) } @@ -286,7 +319,7 @@ func (g *moduleDataGenerator) writeVersionedModuleData(versionCode int, code str } } - g.writeln("}\n\n") + g.writefln("}\n\n") // generate toModuledata method exist := func(name ...string) bool { @@ -298,64 +331,64 @@ func (g *moduleDataGenerator) writeVersionedModuleData(versionCode int, code str return true } - g.writeln("func (md %s) toModuledata() moduledata {", g.generateTypeName(versionCode, bits)) - g.writeln("return moduledata{") + g.writefln("func (md %s) toModuledata() moduledata {", g.generateTypeName(versionCode, bits)) + g.writefln("return moduledata{") if exist("text", "etext") { - g.writeln("TextAddr: %s,", g.wrapValue("md.Text", bits)) - g.writeln("TextLen: %s,", g.wrapValue("md.Etext - md.Text", bits)) + g.writefln("TextAddr: %s,", g.wrapValue("md.Text", bits)) + g.writefln("TextLen: %s,", g.wrapValue("md.Etext - md.Text", bits)) } if exist("noptrdata", "enoptrdata") { - g.writeln("NoPtrDataAddr: %s,", g.wrapValue("md.Noptrdata", bits)) - g.writeln("NoPtrDataLen: %s,", g.wrapValue("md.Enoptrdata - md.Noptrdata", bits)) + g.writefln("NoPtrDataAddr: %s,", g.wrapValue("md.Noptrdata", bits)) + g.writefln("NoPtrDataLen: %s,", g.wrapValue("md.Enoptrdata - md.Noptrdata", bits)) } if exist("data", "edata") { - g.writeln("DataAddr: %s,", g.wrapValue("md.Data", bits)) - g.writeln("DataLen: %s,", g.wrapValue("md.Edata - md.Data", bits)) + g.writefln("DataAddr: %s,", g.wrapValue("md.Data", bits)) + g.writefln("DataLen: %s,", g.wrapValue("md.Edata - md.Data", bits)) } if exist("bss", "ebss") { - g.writeln("BssAddr: %s,", g.wrapValue("md.Bss", bits)) - g.writeln("BssLen: %s,", g.wrapValue("md.Ebss - md.Bss", bits)) + g.writefln("BssAddr: %s,", g.wrapValue("md.Bss", bits)) + g.writefln("BssLen: %s,", g.wrapValue("md.Ebss - md.Bss", bits)) } if exist("noptrbss", "enoptrbss") { - g.writeln("NoPtrBssAddr: %s,", g.wrapValue("md.Noptrbss", bits)) - g.writeln("NoPtrBssLen: %s,", g.wrapValue("md.Enoptrbss - md.Noptrbss", bits)) + g.writefln("NoPtrBssAddr: %s,", g.wrapValue("md.Noptrbss", bits)) + g.writefln("NoPtrBssLen: %s,", g.wrapValue("md.Enoptrbss - md.Noptrbss", bits)) } if exist("types", "etypes") { - g.writeln("TypesAddr: %s,", g.wrapValue("md.Types", bits)) - g.writeln("TypesLen: %s,", g.wrapValue("md.Etypes - md.Types", bits)) + g.writefln("TypesAddr: %s,", g.wrapValue("md.Types", bits)) + g.writefln("TypesLen: %s,", g.wrapValue("md.Etypes - md.Types", bits)) } if exist("typelinks") { - g.writeln("TypelinkAddr: %s,", g.wrapValue("md.Typelinks", bits)) - g.writeln("TypelinkLen: %s,", g.wrapValue("md.Typelinkslen", bits)) + g.writefln("TypelinkAddr: %s,", g.wrapValue("md.Typelinks", bits)) + g.writefln("TypelinkLen: %s,", g.wrapValue("md.Typelinkslen", bits)) } if exist("itablinks") { - g.writeln("ITabLinkAddr: %s,", g.wrapValue("md.Itablinks", bits)) - g.writeln("ITabLinkLen: %s,", g.wrapValue("md.Itablinkslen", bits)) + g.writefln("ITabLinkAddr: %s,", g.wrapValue("md.Itablinks", bits)) + g.writefln("ITabLinkLen: %s,", g.wrapValue("md.Itablinkslen", bits)) } if exist("ftab") { - g.writeln("FuncTabAddr: %s,", g.wrapValue("md.Ftab", bits)) - g.writeln("FuncTabLen: %s,", g.wrapValue("md.Ftablen", bits)) + g.writefln("FuncTabAddr: %s,", g.wrapValue("md.Ftab", bits)) + g.writefln("FuncTabLen: %s,", g.wrapValue("md.Ftablen", bits)) } if exist("pclntable") { - g.writeln("PCLNTabAddr: %s,", g.wrapValue("md.Pclntable", bits)) - g.writeln("PCLNTabLen: %s,", g.wrapValue("md.Pclntablelen", bits)) + g.writefln("PCLNTabAddr: %s,", g.wrapValue("md.Pclntable", bits)) + g.writefln("PCLNTabLen: %s,", g.wrapValue("md.Pclntablelen", bits)) } if exist("gofunc") { - g.writeln("GoFuncVal: %s,", g.wrapValue("md.Gofunc", bits)) + g.writefln("GoFuncVal: %s,", g.wrapValue("md.Gofunc", bits)) } - g.writeln("}\n}\n") + g.writefln("}\n}\n") } writeCode(32) @@ -384,7 +417,9 @@ func generateModuleData() { versionCodes = append(versionCodes, versionCode) } - sort.Ints(versionCodes) + slices.SortFunc(versionCodes, func(a, b int) int { + return -cmp.Compare(a, b) + }) for _, versionCode := range versionCodes { err = g.add(versionCode, sources[versionCode]) @@ -394,6 +429,7 @@ func generateModuleData() { } g.writeSelector() + g.writeModuleListGetter() out, err := format.Source(g.buf.Bytes()) if err != nil { diff --git a/gen/stdpkgs.go b/gen/stdpkgs.go index c6a1a9e..6194443 100644 --- a/gen/stdpkgs.go +++ b/gen/stdpkgs.go @@ -153,7 +153,7 @@ func generateStdPkgs() { return } - if hash == currentHash { + if hash == currentHash && !*forceUpdate { fmt.Println("No need to update " + stdpkgOutputFile) return } diff --git a/goversion.go b/goversion.go index 8b0c2b6..bd8bf93 100644 --- a/goversion.go +++ b/goversion.go @@ -74,6 +74,13 @@ func findGoCompilerVersion(f *GoFile) (*GoVersion, error) { } // Try to determine the version based on the schedinit function. + // FIXME: find a way to resolve cycle dependency + // As for now, tryFromSchedInit has following dependencies: + // tryFromSchedInit -> GetSTDLib -> initPackages -> ensureCompilerVersion + // -> findGoCompilerVersion -> tryFromSchedInit + // so the cycle is created. + // The problem is that we need to resolve moduledata for pclntab to get the correct textStart + // and the moduledata relies on the compiler version. if v := tryFromSchedInit(f); v != nil { return v, nil } @@ -127,35 +134,41 @@ func tryFromSchedInit(f *GoFile) *GoVersion { is32 = true } - // Find schedinit function. - var fcn *Function - std, err := f.GetSTDLib() + // FIXME: disable for now, see the comment in findGoCompilerVersion + // // Find schedinit function. + // var fcn *Function + // std, err := f.GetSTDLib() + // if err != nil { + // return nil + // } + // + //pkgLoop: + // for _, v := range std { + // if v.Name != "runtime" { + // continue + // } + // for _, vv := range v.Functions { + // if vv.Name != "schedinit" { + // continue + // } + // fcn = vv + // break pkgLoop + // } + // } + // + // // Check if the function was found + // if fcn == nil { + // // If we can't find the function there is nothing to do. + // return nil + // } + + addr, size, err := f.fh.getSymbol("runtime.schedinit") if err != nil { return nil } -pkgLoop: - for _, v := range std { - if v.Name != "runtime" { - continue - } - for _, vv := range v.Functions { - if vv.Name != "schedinit" { - continue - } - fcn = vv - break pkgLoop - } - } - - // Check if the function was found - if fcn == nil { - // If we can't find the function there is nothing to do. - return nil - } - // Get the raw hex. - buf, err := f.Bytes(fcn.Offset, fcn.End-fcn.Offset) + buf, err := f.Bytes(addr, size) if err != nil { return nil } @@ -185,12 +198,12 @@ pkgLoop: } // Check what it's loading and if it's pointing to the compiler version used. - // First assume that the address is a direct addressing. + // First, assume that the address is a direct addressing. arg := inst.Args[1].(x86asm.Mem) addr := arg.Disp if arg.Base == x86asm.EIP || arg.Base == x86asm.RIP { // If the addressing is based on the instruction pointer, fix the address. - addr = addr + int64(fcn.Offset) + int64(s) + addr = addr + int64(addr) + int64(s) } // If the addressing is based on the stack pointer, this is not the right @@ -227,7 +240,7 @@ pkgLoop: continue } - // Likely the version string. + // Likely a version string. ver := string(bstr) resolvedVer := ResolveGoVersion(ver) diff --git a/goversion_test.go b/goversion_test.go index acc5fd5..c4a0aa8 100644 --- a/goversion_test.go +++ b/goversion_test.go @@ -102,6 +102,8 @@ func TestVersionComparer(t *testing.T) { } func TestExtractVersionFromInitSched(t *testing.T) { + t.Skip("Gold not contains the unstripped binary") + r := require.New(t) tests := []struct { diff --git a/macho.go b/macho.go index aa181da..1e7435a 100644 --- a/macho.go +++ b/macho.go @@ -19,10 +19,11 @@ package gore import ( "debug/dwarf" - "debug/gosym" "debug/macho" "fmt" "os" + "slices" + "sort" ) func openMachO(fp string) (*machoFile, error) { @@ -35,7 +36,7 @@ func openMachO(fp string) (*machoFile, error) { if err != nil { return nil, fmt.Errorf("error when parsing the Mach-O file: %w", err) } - return &machoFile{file: f, osFile: osFile}, nil + return &machoFile{file: f, osFile: osFile, symtab: newSymbolTableOnce()}, nil } var _ fileHandler = (*machoFile)(nil) @@ -43,6 +44,62 @@ var _ fileHandler = (*machoFile)(nil) type machoFile struct { file *macho.File osFile *os.File + symtab *symbolTableOnce +} + +func (m *machoFile) initSymtab() error { + m.symtab.Do(func() { + if m.file.Symtab == nil { + // just do nothing, keep err nil and table empty + return + } + const stabTypeMask = 0xe0 + // Build a sorted list of addresses of all symbols. + // We infer the size of a symbol by looking at where the next symbol begins. + var addrs []uint64 + for _, s := range m.file.Symtab.Syms { + // Skip stab debug info. + if s.Type&stabTypeMask == 0 { + addrs = append(addrs, s.Value) + } + } + slices.Sort(addrs) + + var syms []symbol + for _, s := range m.file.Symtab.Syms { + if s.Type&stabTypeMask != 0 { + // Skip stab debug info. + continue + } + sym := symbol{Name: s.Name, Value: s.Value} + i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) + if i < len(addrs) { + sym.Size = addrs[i] - s.Value + } + syms = append(syms, sym) + } + + for _, sym := range syms { + m.symtab.table[sym.Name] = sym + } + }) + return m.symtab.err +} + +func (m *machoFile) hasSymbolTable() (bool, error) { + return m.file.Symtab != nil, nil +} + +func (m *machoFile) getSymbol(name string) (uint64, uint64, error) { + err := m.initSymtab() + if err != nil { + return 0, 0, err + } + sym, ok := m.symtab.table[name] + if !ok { + return 0, 0, ErrSymbolNotFound + } + return sym.Value, sym.Size, nil } func (m *machoFile) getParsedFile() any { @@ -61,19 +118,6 @@ func (m *machoFile) Close() error { return m.osFile.Close() } -func (m *machoFile) getPCLNTab() (*gosym.Table, error) { - section := m.file.Section("__gopclntab") - if section == nil { - return nil, ErrNoPCLNTab - } - data, err := section.Data() - if data == nil { - return nil, err - } - pcln := gosym.NewLineTable(data, m.file.Section("__text").Addr) - return gosym.NewTable(nil, pcln) -} - func (m *machoFile) getRData() ([]byte, error) { _, data, err := m.getSectionData("__rodata") return data, err diff --git a/moduledata.go b/moduledata.go index 20143f4..3ed0ad9 100644 --- a/moduledata.go +++ b/moduledata.go @@ -31,6 +31,9 @@ import ( "github.com/goretk/gore/extern/gover" ) +var ErrInvalidModuledata = errors.New("invalid moduledata") +var ErrNoEnoughDataForVMD = errors.New("no enough data to read moduledata") + // Moduledata holds information about the layout of the executable image in memory. type Moduledata interface { // Text returns the text secion. @@ -238,6 +241,10 @@ func pickVersionedModuleData(info *FileInfo) (modulable, error) { bits = 64 } + if info.goversion == nil { + return nil, ErrNoGoVersionFound + } + ver := gover.Parse(extern.StripGo(info.goversion.Name)) zero := gover.Version{} if ver == zero { @@ -256,14 +263,23 @@ func pickVersionedModuleData(info *FileInfo) (modulable, error) { return buf, nil } -func extractModuledata(fileInfo *FileInfo, f fileHandler) (moduledata, error) { - vmd, err := pickVersionedModuleData(fileInfo) +func validateModuledata(md Moduledata, fileInfo *FileInfo, f fileHandler) (bool, error) { + // Take a simple validation step to ensure that the moduledata is valid. + text := md.Text() + + textSectAddr, textSect, err := f.getCodeSection() if err != nil { - return moduledata{}, err + // this is not a failed validation, but a real error needs to be resolved + return false, err } - vmdSize := binary.Size(vmd) + mdTextStart := text.Address + mdTextEnd := text.Address + text.Length + + return textSectAddr <= mdTextStart && mdTextEnd <= textSectAddr+uint64(len(textSect)), nil +} +func searchModuledata(vmd modulable, fileInfo *FileInfo, f fileHandler) (moduledata, error) { _, secData, err := f.getSectionData(f.moduledataSection()) if err != nil { return moduledata{}, err @@ -278,48 +294,186 @@ func extractModuledata(fileInfo *FileInfo, f fileHandler) (moduledata, error) { return moduledata{}, err } -search: - off := bytes.Index(secData, magic) - if off == -1 || len(secData) < off+vmdSize { - return moduledata{}, errors.New("could not find moduledata") + // If we have a versioned moduledata, we can skip the search. + var candidates []modulable + if vmd == nil { + bits := 32 + if fileInfo.WordSize == intSize64 { + bits = 64 + } + candidates, _ = getModuleDataList(bits) } - data := secData[off : off+vmdSize] + // Mark a recoverable error with position information. + type offsetInvalidError struct { + error + offset int + } + + // for search, we always need validation, so the behavior here is different from readModuledataFromSymbol + trySearch := func(vmd modulable, data []byte) (moduledata, error) { + off := bytes.Index(secData, magic) + + if off == -1 { + return moduledata{}, errors.New("could not find pclntab address") + } + + tryLoad := func(vmd modulable, off int) (moduledata, error) { + vmdSize := binary.Size(vmd) + if len(secData) < off+vmdSize { + return moduledata{}, ErrNoEnoughDataForVMD + } + + mdData := secData[off : off+vmdSize] + + // Read the module struct from the file. + r := bytes.NewReader(mdData) + err = binary.Read(r, fileInfo.ByteOrder, vmd) + if err != nil { + return moduledata{}, fmt.Errorf("error when reading module data: %w", err) + } + + // Convert the read struct to the type we return to the caller. + md := vmd.toModuledata() + + valid, err := validateModuledata(md, fileInfo, f) + if err != nil { + return moduledata{}, err + } + if !valid { + return moduledata{}, offsetInvalidError{ErrInvalidModuledata, off} + } + return md, nil + } + + if vmd != nil { + return tryLoad(vmd, off) + } else { + minVmdSize := binary.Size(candidates[0]) + for _, candidateVmd := range candidates { + minVmdSize = min(minVmdSize, binary.Size(candidateVmd)) + } + + for _, candidateVmd := range candidates { + md, err := tryLoad(candidateVmd, off) + if err == nil { + return md, nil + } + } + + if len(secData) < off+minVmdSize { + return moduledata{}, ErrNoEnoughDataForVMD + } + + return moduledata{}, offsetInvalidError{errors.New("could not find moduledata with this match"), off} + } - // Read the module struct from the file. - r := bytes.NewReader(data) - err = binary.Read(r, fileInfo.ByteOrder, vmd) - if err != nil { - return moduledata{}, fmt.Errorf("error when reading module data from file: %w", err) } - // Convert the read struct to the type we return to the caller. - md := vmd.toModuledata() + var offErr offsetInvalidError + current := secData + for { + md, err := trySearch(vmd, current) + if err == nil { + md.fh = f + return md, nil + } + if !errors.As(err, &offErr) { + return moduledata{}, err + } + current = current[offErr.offset+1:] + } +} - // Take a simple validation step to ensure that the moduledata is valid. - text := md.TextAddr - etext := md.TextAddr + md.TextLen +// Normally, we believe the info read from symbol +// is always correct, so no validation is needed. +// But without the goversion a brute force search is needed. +// And the moduledata can be malformed. +func readModuledataFromSymbol(vmd modulable, fileInfo *FileInfo, f fileHandler) (moduledata, error) { + _, addr, err := f.getSymbol("runtime.firstmoduledata") + if err != nil { + return moduledata{}, err + } - textSectAddr, textSect, err := f.getCodeSection() + base, data, err := f.getSectionDataFromAddress(addr) if err != nil { return moduledata{}, err } - if text > etext { - goto invalidMD + + tryLoad := func(vmd modulable, validate bool) (moduledata, error) { + vmdSize := binary.Size(vmd) + if addr-base+uint64(vmdSize) > uint64(len(data)) { + return moduledata{}, errors.New("moduledata is too big") + } + r := bytes.NewReader(data[addr-base : addr-base+uint64(vmdSize)]) + err = binary.Read(r, fileInfo.ByteOrder, vmd) + if err != nil { + return moduledata{}, fmt.Errorf("error when reading module data from file: %w", err) + } + md := vmd.toModuledata() + + if validate { + valid, err := validateModuledata(md, fileInfo, f) + if err != nil { + return moduledata{}, err + } + if !valid { + return moduledata{}, errors.New("moduledata is invalid") + } + } + return md, nil } - if !(textSectAddr <= text && text < textSectAddr+uint64(len(textSect))) { - goto invalidMD + if vmd != nil { + return tryLoad(vmd, true) + } else { + // cannot determine the version, so we have to traverse it + var bits int + if fileInfo.WordSize == intSize32 { + bits = 32 + } else { + bits = 64 + } + + candidates, _ := getModuleDataList(bits) + for _, candidateVmd := range candidates { + // can have error result, need to validate + md, err := tryLoad(candidateVmd, true) + if err == nil { + return md, nil + } + } + return moduledata{}, errors.New("could not find moduledata") } - // Add the file handler. - md.fh = f +} - return md, nil +func extractModuledata(fileInfo *FileInfo, f fileHandler) (moduledata, error) { + vmd, err := pickVersionedModuleData(fileInfo) + if err != nil { + if !errors.Is(err, ErrNoGoVersionFound) { + return moduledata{}, err + } + } -invalidMD: - secData = secData[off+1:] - goto search + hasSymbol, err := f.hasSymbolTable() + if err != nil { + return moduledata{}, err + } + if hasSymbol { + md, err := readModuledataFromSymbol(vmd, fileInfo, f) + if err == nil { + md.fh = f + return md, nil + } + } + + md, err := searchModuledata(vmd, fileInfo, f) + if err != nil { + return moduledata{}, err + } + md.fh = f + return md, nil } func readUIntTo64(r io.Reader, byteOrder binary.ByteOrder, is32bit bool) (addr uint64, err error) { diff --git a/moduledata_gen.go b/moduledata_gen.go index fbaab77..366e65a 100644 --- a/moduledata_gen.go +++ b/moduledata_gen.go @@ -21,30 +21,46 @@ package gore import "fmt" -type moduledata_1_5_32 struct { - Pclntable, Pclntablelen, Pclntablecap uint32 - Ftab, Ftablen, Ftabcap uint32 - Filetab, Filetablen, Filetabcap uint32 - Findfunctab uint32 - Minpc uint32 - Maxpc uint32 - Text uint32 - Etext uint32 - Noptrdata uint32 - Enoptrdata uint32 - Data uint32 - Edata uint32 - Bss uint32 - Ebss uint32 - Noptrbss uint32 - Enoptrbss uint32 - End uint32 - Gcdata uint32 - Gcbss uint32 - Typelinks, Typelinkslen, Typelinkscap uint32 +type moduledata_1_22_32 struct { + PcHeader uint32 + Funcnametab, Funcnametablen, Funcnametabcap uint32 + Cutab, Cutablen, Cutabcap uint32 + Filetab, Filetablen, Filetabcap uint32 + Pctab, Pctablen, Pctabcap uint32 + Pclntable, Pclntablelen, Pclntablecap uint32 + Ftab, Ftablen, Ftabcap uint32 + Findfunctab uint32 + Minpc uint32 + Maxpc uint32 + Text uint32 + Etext uint32 + Noptrdata uint32 + Enoptrdata uint32 + Data uint32 + Edata uint32 + Bss uint32 + Ebss uint32 + Noptrbss uint32 + Enoptrbss uint32 + Covctrs uint32 + Ecovctrs uint32 + End uint32 + Gcdata uint32 + Gcbss uint32 + Types uint32 + Etypes uint32 + Rodata uint32 + Gofunc uint32 + Textsectmap, Textsectmaplen, Textsectmapcap uint32 + Typelinks, Typelinkslen, Typelinkscap uint32 + Itablinks, Itablinkslen, Itablinkscap uint32 + Ptab, Ptablen, Ptabcap uint32 + Pluginpath, Pluginpathlen uint32 + Pkghashes, Pkghasheslen, Pkghashescap uint32 + Inittasks, Inittaskslen, Inittaskscap uint32 } -func (md moduledata_1_5_32) toModuledata() moduledata { +func (md moduledata_1_22_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -56,39 +72,60 @@ func (md moduledata_1_5_32) toModuledata() moduledata { BssLen: uint64(md.Ebss - md.Bss), NoPtrBssAddr: uint64(md.Noptrbss), NoPtrBssLen: uint64(md.Enoptrbss - md.Noptrbss), + TypesAddr: uint64(md.Types), + TypesLen: uint64(md.Etypes - md.Types), TypelinkAddr: uint64(md.Typelinks), TypelinkLen: uint64(md.Typelinkslen), + ITabLinkAddr: uint64(md.Itablinks), + ITabLinkLen: uint64(md.Itablinkslen), FuncTabAddr: uint64(md.Ftab), FuncTabLen: uint64(md.Ftablen), PCLNTabAddr: uint64(md.Pclntable), PCLNTabLen: uint64(md.Pclntablelen), + GoFuncVal: uint64(md.Gofunc), } } -type moduledata_1_5_64 struct { - Pclntable, Pclntablelen, Pclntablecap uint64 - Ftab, Ftablen, Ftabcap uint64 - Filetab, Filetablen, Filetabcap uint64 - Findfunctab uint64 - Minpc uint64 - Maxpc uint64 - Text uint64 - Etext uint64 - Noptrdata uint64 - Enoptrdata uint64 - Data uint64 - Edata uint64 - Bss uint64 - Ebss uint64 - Noptrbss uint64 - Enoptrbss uint64 - End uint64 - Gcdata uint64 - Gcbss uint64 - Typelinks, Typelinkslen, Typelinkscap uint64 +type moduledata_1_22_64 struct { + PcHeader uint64 + Funcnametab, Funcnametablen, Funcnametabcap uint64 + Cutab, Cutablen, Cutabcap uint64 + Filetab, Filetablen, Filetabcap uint64 + Pctab, Pctablen, Pctabcap uint64 + Pclntable, Pclntablelen, Pclntablecap uint64 + Ftab, Ftablen, Ftabcap uint64 + Findfunctab uint64 + Minpc uint64 + Maxpc uint64 + Text uint64 + Etext uint64 + Noptrdata uint64 + Enoptrdata uint64 + Data uint64 + Edata uint64 + Bss uint64 + Ebss uint64 + Noptrbss uint64 + Enoptrbss uint64 + Covctrs uint64 + Ecovctrs uint64 + End uint64 + Gcdata uint64 + Gcbss uint64 + Types uint64 + Etypes uint64 + Rodata uint64 + Gofunc uint64 + Textsectmap, Textsectmaplen, Textsectmapcap uint64 + Typelinks, Typelinkslen, Typelinkscap uint64 + Itablinks, Itablinkslen, Itablinkscap uint64 + Ptab, Ptablen, Ptabcap uint64 + Pluginpath, Pluginpathlen uint64 + Pkghashes, Pkghasheslen, Pkghashescap uint64 + Inittasks, Inittaskslen, Inittaskscap uint64 } -func (md moduledata_1_5_64) toModuledata() moduledata { +func (md moduledata_1_22_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -100,39 +137,60 @@ func (md moduledata_1_5_64) toModuledata() moduledata { BssLen: md.Ebss - md.Bss, NoPtrBssAddr: md.Noptrbss, NoPtrBssLen: md.Enoptrbss - md.Noptrbss, + TypesAddr: md.Types, + TypesLen: md.Etypes - md.Types, TypelinkAddr: md.Typelinks, TypelinkLen: md.Typelinkslen, + ITabLinkAddr: md.Itablinks, + ITabLinkLen: md.Itablinkslen, FuncTabAddr: md.Ftab, FuncTabLen: md.Ftablen, PCLNTabAddr: md.Pclntable, PCLNTabLen: md.Pclntablelen, + GoFuncVal: md.Gofunc, } } -type moduledata_1_6_32 struct { - Pclntable, Pclntablelen, Pclntablecap uint32 - Ftab, Ftablen, Ftabcap uint32 - Filetab, Filetablen, Filetabcap uint32 - Findfunctab uint32 - Minpc uint32 - Maxpc uint32 - Text uint32 - Etext uint32 - Noptrdata uint32 - Enoptrdata uint32 - Data uint32 - Edata uint32 - Bss uint32 - Ebss uint32 - Noptrbss uint32 - Enoptrbss uint32 - End uint32 - Gcdata uint32 - Gcbss uint32 - Typelinks, Typelinkslen, Typelinkscap uint32 +type moduledata_1_21_32 struct { + PcHeader uint32 + Funcnametab, Funcnametablen, Funcnametabcap uint32 + Cutab, Cutablen, Cutabcap uint32 + Filetab, Filetablen, Filetabcap uint32 + Pctab, Pctablen, Pctabcap uint32 + Pclntable, Pclntablelen, Pclntablecap uint32 + Ftab, Ftablen, Ftabcap uint32 + Findfunctab uint32 + Minpc uint32 + Maxpc uint32 + Text uint32 + Etext uint32 + Noptrdata uint32 + Enoptrdata uint32 + Data uint32 + Edata uint32 + Bss uint32 + Ebss uint32 + Noptrbss uint32 + Enoptrbss uint32 + Covctrs uint32 + Ecovctrs uint32 + End uint32 + Gcdata uint32 + Gcbss uint32 + Types uint32 + Etypes uint32 + Rodata uint32 + Gofunc uint32 + Textsectmap, Textsectmaplen, Textsectmapcap uint32 + Typelinks, Typelinkslen, Typelinkscap uint32 + Itablinks, Itablinkslen, Itablinkscap uint32 + Ptab, Ptablen, Ptabcap uint32 + Pluginpath, Pluginpathlen uint32 + Pkghashes, Pkghasheslen, Pkghashescap uint32 + Inittasks, Inittaskslen, Inittaskscap uint32 } -func (md moduledata_1_6_32) toModuledata() moduledata { +func (md moduledata_1_21_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -144,137 +202,60 @@ func (md moduledata_1_6_32) toModuledata() moduledata { BssLen: uint64(md.Ebss - md.Bss), NoPtrBssAddr: uint64(md.Noptrbss), NoPtrBssLen: uint64(md.Enoptrbss - md.Noptrbss), + TypesAddr: uint64(md.Types), + TypesLen: uint64(md.Etypes - md.Types), TypelinkAddr: uint64(md.Typelinks), TypelinkLen: uint64(md.Typelinkslen), + ITabLinkAddr: uint64(md.Itablinks), + ITabLinkLen: uint64(md.Itablinkslen), FuncTabAddr: uint64(md.Ftab), FuncTabLen: uint64(md.Ftablen), PCLNTabAddr: uint64(md.Pclntable), PCLNTabLen: uint64(md.Pclntablelen), + GoFuncVal: uint64(md.Gofunc), } } -type moduledata_1_6_64 struct { - Pclntable, Pclntablelen, Pclntablecap uint64 - Ftab, Ftablen, Ftabcap uint64 - Filetab, Filetablen, Filetabcap uint64 - Findfunctab uint64 - Minpc uint64 - Maxpc uint64 - Text uint64 - Etext uint64 - Noptrdata uint64 - Enoptrdata uint64 - Data uint64 - Edata uint64 - Bss uint64 - Ebss uint64 - Noptrbss uint64 - Enoptrbss uint64 - End uint64 - Gcdata uint64 - Gcbss uint64 - Typelinks, Typelinkslen, Typelinkscap uint64 +type moduledata_1_21_64 struct { + PcHeader uint64 + Funcnametab, Funcnametablen, Funcnametabcap uint64 + Cutab, Cutablen, Cutabcap uint64 + Filetab, Filetablen, Filetabcap uint64 + Pctab, Pctablen, Pctabcap uint64 + Pclntable, Pclntablelen, Pclntablecap uint64 + Ftab, Ftablen, Ftabcap uint64 + Findfunctab uint64 + Minpc uint64 + Maxpc uint64 + Text uint64 + Etext uint64 + Noptrdata uint64 + Enoptrdata uint64 + Data uint64 + Edata uint64 + Bss uint64 + Ebss uint64 + Noptrbss uint64 + Enoptrbss uint64 + Covctrs uint64 + Ecovctrs uint64 + End uint64 + Gcdata uint64 + Gcbss uint64 + Types uint64 + Etypes uint64 + Rodata uint64 + Gofunc uint64 + Textsectmap, Textsectmaplen, Textsectmapcap uint64 + Typelinks, Typelinkslen, Typelinkscap uint64 + Itablinks, Itablinkslen, Itablinkscap uint64 + Ptab, Ptablen, Ptabcap uint64 + Pluginpath, Pluginpathlen uint64 + Pkghashes, Pkghasheslen, Pkghashescap uint64 + Inittasks, Inittaskslen, Inittaskscap uint64 } -func (md moduledata_1_6_64) toModuledata() moduledata { - return moduledata{ - TextAddr: md.Text, - TextLen: md.Etext - md.Text, - NoPtrDataAddr: md.Noptrdata, - NoPtrDataLen: md.Enoptrdata - md.Noptrdata, - DataAddr: md.Data, - DataLen: md.Edata - md.Data, - BssAddr: md.Bss, - BssLen: md.Ebss - md.Bss, - NoPtrBssAddr: md.Noptrbss, - NoPtrBssLen: md.Enoptrbss - md.Noptrbss, - TypelinkAddr: md.Typelinks, - TypelinkLen: md.Typelinkslen, - FuncTabAddr: md.Ftab, - FuncTabLen: md.Ftablen, - PCLNTabAddr: md.Pclntable, - PCLNTabLen: md.Pclntablelen, - } -} - -type moduledata_1_7_32 struct { - Pclntable, Pclntablelen, Pclntablecap uint32 - Ftab, Ftablen, Ftabcap uint32 - Filetab, Filetablen, Filetabcap uint32 - Findfunctab uint32 - Minpc uint32 - Maxpc uint32 - Text uint32 - Etext uint32 - Noptrdata uint32 - Enoptrdata uint32 - Data uint32 - Edata uint32 - Bss uint32 - Ebss uint32 - Noptrbss uint32 - Enoptrbss uint32 - End uint32 - Gcdata uint32 - Gcbss uint32 - Types uint32 - Etypes uint32 - Typelinks, Typelinkslen, Typelinkscap uint32 - Itablinks, Itablinkslen, Itablinkscap uint32 -} - -func (md moduledata_1_7_32) toModuledata() moduledata { - return moduledata{ - TextAddr: uint64(md.Text), - TextLen: uint64(md.Etext - md.Text), - NoPtrDataAddr: uint64(md.Noptrdata), - NoPtrDataLen: uint64(md.Enoptrdata - md.Noptrdata), - DataAddr: uint64(md.Data), - DataLen: uint64(md.Edata - md.Data), - BssAddr: uint64(md.Bss), - BssLen: uint64(md.Ebss - md.Bss), - NoPtrBssAddr: uint64(md.Noptrbss), - NoPtrBssLen: uint64(md.Enoptrbss - md.Noptrbss), - TypesAddr: uint64(md.Types), - TypesLen: uint64(md.Etypes - md.Types), - TypelinkAddr: uint64(md.Typelinks), - TypelinkLen: uint64(md.Typelinkslen), - ITabLinkAddr: uint64(md.Itablinks), - ITabLinkLen: uint64(md.Itablinkslen), - FuncTabAddr: uint64(md.Ftab), - FuncTabLen: uint64(md.Ftablen), - PCLNTabAddr: uint64(md.Pclntable), - PCLNTabLen: uint64(md.Pclntablelen), - } -} - -type moduledata_1_7_64 struct { - Pclntable, Pclntablelen, Pclntablecap uint64 - Ftab, Ftablen, Ftabcap uint64 - Filetab, Filetablen, Filetabcap uint64 - Findfunctab uint64 - Minpc uint64 - Maxpc uint64 - Text uint64 - Etext uint64 - Noptrdata uint64 - Enoptrdata uint64 - Data uint64 - Edata uint64 - Bss uint64 - Ebss uint64 - Noptrbss uint64 - Enoptrbss uint64 - End uint64 - Gcdata uint64 - Gcbss uint64 - Types uint64 - Etypes uint64 - Typelinks, Typelinkslen, Typelinkscap uint64 - Itablinks, Itablinkslen, Itablinkscap uint64 -} - -func (md moduledata_1_7_64) toModuledata() moduledata { +func (md moduledata_1_21_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -296,13 +277,18 @@ func (md moduledata_1_7_64) toModuledata() moduledata { FuncTabLen: md.Ftablen, PCLNTabAddr: md.Pclntable, PCLNTabLen: md.Pclntablelen, + GoFuncVal: md.Gofunc, } } -type moduledata_1_8_32 struct { +type moduledata_1_20_32 struct { + PcHeader uint32 + Funcnametab, Funcnametablen, Funcnametabcap uint32 + Cutab, Cutablen, Cutabcap uint32 + Filetab, Filetablen, Filetabcap uint32 + Pctab, Pctablen, Pctabcap uint32 Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 - Filetab, Filetablen, Filetabcap uint32 Findfunctab uint32 Minpc uint32 Maxpc uint32 @@ -316,11 +302,15 @@ type moduledata_1_8_32 struct { Ebss uint32 Noptrbss uint32 Enoptrbss uint32 + Covctrs uint32 + Ecovctrs uint32 End uint32 Gcdata uint32 Gcbss uint32 Types uint32 Etypes uint32 + Rodata uint32 + Gofunc uint32 Textsectmap, Textsectmaplen, Textsectmapcap uint32 Typelinks, Typelinkslen, Typelinkscap uint32 Itablinks, Itablinkslen, Itablinkscap uint32 @@ -329,7 +319,7 @@ type moduledata_1_8_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_8_32) toModuledata() moduledata { +func (md moduledata_1_20_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -351,13 +341,18 @@ func (md moduledata_1_8_32) toModuledata() moduledata { FuncTabLen: uint64(md.Ftablen), PCLNTabAddr: uint64(md.Pclntable), PCLNTabLen: uint64(md.Pclntablelen), + GoFuncVal: uint64(md.Gofunc), } } -type moduledata_1_8_64 struct { +type moduledata_1_20_64 struct { + PcHeader uint64 + Funcnametab, Funcnametablen, Funcnametabcap uint64 + Cutab, Cutablen, Cutabcap uint64 + Filetab, Filetablen, Filetabcap uint64 + Pctab, Pctablen, Pctabcap uint64 Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 - Filetab, Filetablen, Filetabcap uint64 Findfunctab uint64 Minpc uint64 Maxpc uint64 @@ -371,11 +366,15 @@ type moduledata_1_8_64 struct { Ebss uint64 Noptrbss uint64 Enoptrbss uint64 + Covctrs uint64 + Ecovctrs uint64 End uint64 Gcdata uint64 Gcbss uint64 Types uint64 Etypes uint64 + Rodata uint64 + Gofunc uint64 Textsectmap, Textsectmaplen, Textsectmapcap uint64 Typelinks, Typelinkslen, Typelinkscap uint64 Itablinks, Itablinkslen, Itablinkscap uint64 @@ -384,7 +383,7 @@ type moduledata_1_8_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_8_64) toModuledata() moduledata { +func (md moduledata_1_20_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -406,13 +405,18 @@ func (md moduledata_1_8_64) toModuledata() moduledata { FuncTabLen: md.Ftablen, PCLNTabAddr: md.Pclntable, PCLNTabLen: md.Pclntablelen, + GoFuncVal: md.Gofunc, } } -type moduledata_1_9_32 struct { +type moduledata_1_19_32 struct { + PcHeader uint32 + Funcnametab, Funcnametablen, Funcnametabcap uint32 + Cutab, Cutablen, Cutabcap uint32 + Filetab, Filetablen, Filetabcap uint32 + Pctab, Pctablen, Pctabcap uint32 Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 - Filetab, Filetablen, Filetabcap uint32 Findfunctab uint32 Minpc uint32 Maxpc uint32 @@ -431,6 +435,8 @@ type moduledata_1_9_32 struct { Gcbss uint32 Types uint32 Etypes uint32 + Rodata uint32 + Gofunc uint32 Textsectmap, Textsectmaplen, Textsectmapcap uint32 Typelinks, Typelinkslen, Typelinkscap uint32 Itablinks, Itablinkslen, Itablinkscap uint32 @@ -439,7 +445,7 @@ type moduledata_1_9_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_9_32) toModuledata() moduledata { +func (md moduledata_1_19_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -461,13 +467,18 @@ func (md moduledata_1_9_32) toModuledata() moduledata { FuncTabLen: uint64(md.Ftablen), PCLNTabAddr: uint64(md.Pclntable), PCLNTabLen: uint64(md.Pclntablelen), + GoFuncVal: uint64(md.Gofunc), } } -type moduledata_1_9_64 struct { +type moduledata_1_19_64 struct { + PcHeader uint64 + Funcnametab, Funcnametablen, Funcnametabcap uint64 + Cutab, Cutablen, Cutabcap uint64 + Filetab, Filetablen, Filetabcap uint64 + Pctab, Pctablen, Pctabcap uint64 Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 - Filetab, Filetablen, Filetabcap uint64 Findfunctab uint64 Minpc uint64 Maxpc uint64 @@ -486,6 +497,8 @@ type moduledata_1_9_64 struct { Gcbss uint64 Types uint64 Etypes uint64 + Rodata uint64 + Gofunc uint64 Textsectmap, Textsectmaplen, Textsectmapcap uint64 Typelinks, Typelinkslen, Typelinkscap uint64 Itablinks, Itablinkslen, Itablinkscap uint64 @@ -494,7 +507,7 @@ type moduledata_1_9_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_9_64) toModuledata() moduledata { +func (md moduledata_1_19_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -516,13 +529,18 @@ func (md moduledata_1_9_64) toModuledata() moduledata { FuncTabLen: md.Ftablen, PCLNTabAddr: md.Pclntable, PCLNTabLen: md.Pclntablelen, + GoFuncVal: md.Gofunc, } } -type moduledata_1_10_32 struct { +type moduledata_1_18_32 struct { + PcHeader uint32 + Funcnametab, Funcnametablen, Funcnametabcap uint32 + Cutab, Cutablen, Cutabcap uint32 + Filetab, Filetablen, Filetabcap uint32 + Pctab, Pctablen, Pctabcap uint32 Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 - Filetab, Filetablen, Filetabcap uint32 Findfunctab uint32 Minpc uint32 Maxpc uint32 @@ -541,6 +559,8 @@ type moduledata_1_10_32 struct { Gcbss uint32 Types uint32 Etypes uint32 + Rodata uint32 + Gofunc uint32 Textsectmap, Textsectmaplen, Textsectmapcap uint32 Typelinks, Typelinkslen, Typelinkscap uint32 Itablinks, Itablinkslen, Itablinkscap uint32 @@ -549,7 +569,7 @@ type moduledata_1_10_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_10_32) toModuledata() moduledata { +func (md moduledata_1_18_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -571,13 +591,18 @@ func (md moduledata_1_10_32) toModuledata() moduledata { FuncTabLen: uint64(md.Ftablen), PCLNTabAddr: uint64(md.Pclntable), PCLNTabLen: uint64(md.Pclntablelen), + GoFuncVal: uint64(md.Gofunc), } } -type moduledata_1_10_64 struct { +type moduledata_1_18_64 struct { + PcHeader uint64 + Funcnametab, Funcnametablen, Funcnametabcap uint64 + Cutab, Cutablen, Cutabcap uint64 + Filetab, Filetablen, Filetabcap uint64 + Pctab, Pctablen, Pctabcap uint64 Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 - Filetab, Filetablen, Filetabcap uint64 Findfunctab uint64 Minpc uint64 Maxpc uint64 @@ -596,6 +621,8 @@ type moduledata_1_10_64 struct { Gcbss uint64 Types uint64 Etypes uint64 + Rodata uint64 + Gofunc uint64 Textsectmap, Textsectmaplen, Textsectmapcap uint64 Typelinks, Typelinkslen, Typelinkscap uint64 Itablinks, Itablinkslen, Itablinkscap uint64 @@ -604,7 +631,7 @@ type moduledata_1_10_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_10_64) toModuledata() moduledata { +func (md moduledata_1_18_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -626,13 +653,18 @@ func (md moduledata_1_10_64) toModuledata() moduledata { FuncTabLen: md.Ftablen, PCLNTabAddr: md.Pclntable, PCLNTabLen: md.Pclntablelen, + GoFuncVal: md.Gofunc, } } -type moduledata_1_11_32 struct { +type moduledata_1_17_32 struct { + PcHeader uint32 + Funcnametab, Funcnametablen, Funcnametabcap uint32 + Cutab, Cutablen, Cutabcap uint32 + Filetab, Filetablen, Filetabcap uint32 + Pctab, Pctablen, Pctabcap uint32 Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 - Filetab, Filetablen, Filetabcap uint32 Findfunctab uint32 Minpc uint32 Maxpc uint32 @@ -659,7 +691,7 @@ type moduledata_1_11_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_11_32) toModuledata() moduledata { +func (md moduledata_1_17_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -684,10 +716,14 @@ func (md moduledata_1_11_32) toModuledata() moduledata { } } -type moduledata_1_11_64 struct { +type moduledata_1_17_64 struct { + PcHeader uint64 + Funcnametab, Funcnametablen, Funcnametabcap uint64 + Cutab, Cutablen, Cutabcap uint64 + Filetab, Filetablen, Filetabcap uint64 + Pctab, Pctablen, Pctabcap uint64 Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 - Filetab, Filetablen, Filetabcap uint64 Findfunctab uint64 Minpc uint64 Maxpc uint64 @@ -714,7 +750,7 @@ type moduledata_1_11_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_11_64) toModuledata() moduledata { +func (md moduledata_1_17_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -739,10 +775,14 @@ func (md moduledata_1_11_64) toModuledata() moduledata { } } -type moduledata_1_12_32 struct { +type moduledata_1_16_32 struct { + PcHeader uint32 + Funcnametab, Funcnametablen, Funcnametabcap uint32 + Cutab, Cutablen, Cutabcap uint32 + Filetab, Filetablen, Filetabcap uint32 + Pctab, Pctablen, Pctabcap uint32 Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 - Filetab, Filetablen, Filetabcap uint32 Findfunctab uint32 Minpc uint32 Maxpc uint32 @@ -769,7 +809,7 @@ type moduledata_1_12_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_12_32) toModuledata() moduledata { +func (md moduledata_1_16_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -794,10 +834,14 @@ func (md moduledata_1_12_32) toModuledata() moduledata { } } -type moduledata_1_12_64 struct { +type moduledata_1_16_64 struct { + PcHeader uint64 + Funcnametab, Funcnametablen, Funcnametabcap uint64 + Cutab, Cutablen, Cutabcap uint64 + Filetab, Filetablen, Filetabcap uint64 + Pctab, Pctablen, Pctabcap uint64 Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 - Filetab, Filetablen, Filetabcap uint64 Findfunctab uint64 Minpc uint64 Maxpc uint64 @@ -824,7 +868,7 @@ type moduledata_1_12_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_12_64) toModuledata() moduledata { +func (md moduledata_1_16_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -849,7 +893,7 @@ func (md moduledata_1_12_64) toModuledata() moduledata { } } -type moduledata_1_13_32 struct { +type moduledata_1_15_32 struct { Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 Filetab, Filetablen, Filetabcap uint32 @@ -879,7 +923,7 @@ type moduledata_1_13_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_13_32) toModuledata() moduledata { +func (md moduledata_1_15_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -904,7 +948,7 @@ func (md moduledata_1_13_32) toModuledata() moduledata { } } -type moduledata_1_13_64 struct { +type moduledata_1_15_64 struct { Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 Filetab, Filetablen, Filetabcap uint64 @@ -934,7 +978,7 @@ type moduledata_1_13_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_13_64) toModuledata() moduledata { +func (md moduledata_1_15_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -1069,7 +1113,7 @@ func (md moduledata_1_14_64) toModuledata() moduledata { } } -type moduledata_1_15_32 struct { +type moduledata_1_13_32 struct { Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 Filetab, Filetablen, Filetabcap uint32 @@ -1099,7 +1143,7 @@ type moduledata_1_15_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_15_32) toModuledata() moduledata { +func (md moduledata_1_13_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -1124,7 +1168,7 @@ func (md moduledata_1_15_32) toModuledata() moduledata { } } -type moduledata_1_15_64 struct { +type moduledata_1_13_64 struct { Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 Filetab, Filetablen, Filetabcap uint64 @@ -1154,7 +1198,7 @@ type moduledata_1_15_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_15_64) toModuledata() moduledata { +func (md moduledata_1_13_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -1179,14 +1223,10 @@ func (md moduledata_1_15_64) toModuledata() moduledata { } } -type moduledata_1_16_32 struct { - PcHeader uint32 - Funcnametab, Funcnametablen, Funcnametabcap uint32 - Cutab, Cutablen, Cutabcap uint32 - Filetab, Filetablen, Filetabcap uint32 - Pctab, Pctablen, Pctabcap uint32 +type moduledata_1_12_32 struct { Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 + Filetab, Filetablen, Filetabcap uint32 Findfunctab uint32 Minpc uint32 Maxpc uint32 @@ -1213,7 +1253,7 @@ type moduledata_1_16_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_16_32) toModuledata() moduledata { +func (md moduledata_1_12_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -1238,14 +1278,10 @@ func (md moduledata_1_16_32) toModuledata() moduledata { } } -type moduledata_1_16_64 struct { - PcHeader uint64 - Funcnametab, Funcnametablen, Funcnametabcap uint64 - Cutab, Cutablen, Cutabcap uint64 - Filetab, Filetablen, Filetabcap uint64 - Pctab, Pctablen, Pctabcap uint64 +type moduledata_1_12_64 struct { Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 + Filetab, Filetablen, Filetabcap uint64 Findfunctab uint64 Minpc uint64 Maxpc uint64 @@ -1272,7 +1308,7 @@ type moduledata_1_16_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_16_64) toModuledata() moduledata { +func (md moduledata_1_12_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -1297,14 +1333,10 @@ func (md moduledata_1_16_64) toModuledata() moduledata { } } -type moduledata_1_17_32 struct { - PcHeader uint32 - Funcnametab, Funcnametablen, Funcnametabcap uint32 - Cutab, Cutablen, Cutabcap uint32 - Filetab, Filetablen, Filetabcap uint32 - Pctab, Pctablen, Pctabcap uint32 +type moduledata_1_11_32 struct { Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 + Filetab, Filetablen, Filetabcap uint32 Findfunctab uint32 Minpc uint32 Maxpc uint32 @@ -1331,7 +1363,7 @@ type moduledata_1_17_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_17_32) toModuledata() moduledata { +func (md moduledata_1_11_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -1356,14 +1388,10 @@ func (md moduledata_1_17_32) toModuledata() moduledata { } } -type moduledata_1_17_64 struct { - PcHeader uint64 - Funcnametab, Funcnametablen, Funcnametabcap uint64 - Cutab, Cutablen, Cutabcap uint64 - Filetab, Filetablen, Filetabcap uint64 - Pctab, Pctablen, Pctabcap uint64 +type moduledata_1_11_64 struct { Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 + Filetab, Filetablen, Filetabcap uint64 Findfunctab uint64 Minpc uint64 Maxpc uint64 @@ -1390,7 +1418,7 @@ type moduledata_1_17_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_17_64) toModuledata() moduledata { +func (md moduledata_1_11_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -1415,14 +1443,10 @@ func (md moduledata_1_17_64) toModuledata() moduledata { } } -type moduledata_1_18_32 struct { - PcHeader uint32 - Funcnametab, Funcnametablen, Funcnametabcap uint32 - Cutab, Cutablen, Cutabcap uint32 - Filetab, Filetablen, Filetabcap uint32 - Pctab, Pctablen, Pctabcap uint32 +type moduledata_1_10_32 struct { Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 + Filetab, Filetablen, Filetabcap uint32 Findfunctab uint32 Minpc uint32 Maxpc uint32 @@ -1441,8 +1465,6 @@ type moduledata_1_18_32 struct { Gcbss uint32 Types uint32 Etypes uint32 - Rodata uint32 - Gofunc uint32 Textsectmap, Textsectmaplen, Textsectmapcap uint32 Typelinks, Typelinkslen, Typelinkscap uint32 Itablinks, Itablinkslen, Itablinkscap uint32 @@ -1451,7 +1473,7 @@ type moduledata_1_18_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_18_32) toModuledata() moduledata { +func (md moduledata_1_10_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -1473,18 +1495,13 @@ func (md moduledata_1_18_32) toModuledata() moduledata { FuncTabLen: uint64(md.Ftablen), PCLNTabAddr: uint64(md.Pclntable), PCLNTabLen: uint64(md.Pclntablelen), - GoFuncVal: uint64(md.Gofunc), } } -type moduledata_1_18_64 struct { - PcHeader uint64 - Funcnametab, Funcnametablen, Funcnametabcap uint64 - Cutab, Cutablen, Cutabcap uint64 - Filetab, Filetablen, Filetabcap uint64 - Pctab, Pctablen, Pctabcap uint64 +type moduledata_1_10_64 struct { Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 + Filetab, Filetablen, Filetabcap uint64 Findfunctab uint64 Minpc uint64 Maxpc uint64 @@ -1503,8 +1520,6 @@ type moduledata_1_18_64 struct { Gcbss uint64 Types uint64 Etypes uint64 - Rodata uint64 - Gofunc uint64 Textsectmap, Textsectmaplen, Textsectmapcap uint64 Typelinks, Typelinkslen, Typelinkscap uint64 Itablinks, Itablinkslen, Itablinkscap uint64 @@ -1513,7 +1528,7 @@ type moduledata_1_18_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_18_64) toModuledata() moduledata { +func (md moduledata_1_10_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -1535,18 +1550,13 @@ func (md moduledata_1_18_64) toModuledata() moduledata { FuncTabLen: md.Ftablen, PCLNTabAddr: md.Pclntable, PCLNTabLen: md.Pclntablelen, - GoFuncVal: md.Gofunc, } } -type moduledata_1_19_32 struct { - PcHeader uint32 - Funcnametab, Funcnametablen, Funcnametabcap uint32 - Cutab, Cutablen, Cutabcap uint32 - Filetab, Filetablen, Filetabcap uint32 - Pctab, Pctablen, Pctabcap uint32 +type moduledata_1_9_32 struct { Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 + Filetab, Filetablen, Filetabcap uint32 Findfunctab uint32 Minpc uint32 Maxpc uint32 @@ -1565,8 +1575,6 @@ type moduledata_1_19_32 struct { Gcbss uint32 Types uint32 Etypes uint32 - Rodata uint32 - Gofunc uint32 Textsectmap, Textsectmaplen, Textsectmapcap uint32 Typelinks, Typelinkslen, Typelinkscap uint32 Itablinks, Itablinkslen, Itablinkscap uint32 @@ -1575,7 +1583,7 @@ type moduledata_1_19_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_19_32) toModuledata() moduledata { +func (md moduledata_1_9_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -1597,18 +1605,13 @@ func (md moduledata_1_19_32) toModuledata() moduledata { FuncTabLen: uint64(md.Ftablen), PCLNTabAddr: uint64(md.Pclntable), PCLNTabLen: uint64(md.Pclntablelen), - GoFuncVal: uint64(md.Gofunc), } } -type moduledata_1_19_64 struct { - PcHeader uint64 - Funcnametab, Funcnametablen, Funcnametabcap uint64 - Cutab, Cutablen, Cutabcap uint64 - Filetab, Filetablen, Filetabcap uint64 - Pctab, Pctablen, Pctabcap uint64 +type moduledata_1_9_64 struct { Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 + Filetab, Filetablen, Filetabcap uint64 Findfunctab uint64 Minpc uint64 Maxpc uint64 @@ -1627,8 +1630,6 @@ type moduledata_1_19_64 struct { Gcbss uint64 Types uint64 Etypes uint64 - Rodata uint64 - Gofunc uint64 Textsectmap, Textsectmaplen, Textsectmapcap uint64 Typelinks, Typelinkslen, Typelinkscap uint64 Itablinks, Itablinkslen, Itablinkscap uint64 @@ -1637,7 +1638,7 @@ type moduledata_1_19_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_19_64) toModuledata() moduledata { +func (md moduledata_1_9_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -1659,18 +1660,13 @@ func (md moduledata_1_19_64) toModuledata() moduledata { FuncTabLen: md.Ftablen, PCLNTabAddr: md.Pclntable, PCLNTabLen: md.Pclntablelen, - GoFuncVal: md.Gofunc, } } -type moduledata_1_20_32 struct { - PcHeader uint32 - Funcnametab, Funcnametablen, Funcnametabcap uint32 - Cutab, Cutablen, Cutabcap uint32 - Filetab, Filetablen, Filetabcap uint32 - Pctab, Pctablen, Pctabcap uint32 +type moduledata_1_8_32 struct { Pclntable, Pclntablelen, Pclntablecap uint32 Ftab, Ftablen, Ftabcap uint32 + Filetab, Filetablen, Filetabcap uint32 Findfunctab uint32 Minpc uint32 Maxpc uint32 @@ -1684,15 +1680,11 @@ type moduledata_1_20_32 struct { Ebss uint32 Noptrbss uint32 Enoptrbss uint32 - Covctrs uint32 - Ecovctrs uint32 End uint32 Gcdata uint32 Gcbss uint32 Types uint32 Etypes uint32 - Rodata uint32 - Gofunc uint32 Textsectmap, Textsectmaplen, Textsectmapcap uint32 Typelinks, Typelinkslen, Typelinkscap uint32 Itablinks, Itablinkslen, Itablinkscap uint32 @@ -1701,7 +1693,7 @@ type moduledata_1_20_32 struct { Pkghashes, Pkghasheslen, Pkghashescap uint32 } -func (md moduledata_1_20_32) toModuledata() moduledata { +func (md moduledata_1_8_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -1723,18 +1715,13 @@ func (md moduledata_1_20_32) toModuledata() moduledata { FuncTabLen: uint64(md.Ftablen), PCLNTabAddr: uint64(md.Pclntable), PCLNTabLen: uint64(md.Pclntablelen), - GoFuncVal: uint64(md.Gofunc), } } -type moduledata_1_20_64 struct { - PcHeader uint64 - Funcnametab, Funcnametablen, Funcnametabcap uint64 - Cutab, Cutablen, Cutabcap uint64 - Filetab, Filetablen, Filetabcap uint64 - Pctab, Pctablen, Pctabcap uint64 +type moduledata_1_8_64 struct { Pclntable, Pclntablelen, Pclntablecap uint64 Ftab, Ftablen, Ftabcap uint64 + Filetab, Filetablen, Filetabcap uint64 Findfunctab uint64 Minpc uint64 Maxpc uint64 @@ -1748,15 +1735,11 @@ type moduledata_1_20_64 struct { Ebss uint64 Noptrbss uint64 Enoptrbss uint64 - Covctrs uint64 - Ecovctrs uint64 End uint64 Gcdata uint64 Gcbss uint64 Types uint64 Etypes uint64 - Rodata uint64 - Gofunc uint64 Textsectmap, Textsectmaplen, Textsectmapcap uint64 Typelinks, Typelinkslen, Typelinkscap uint64 Itablinks, Itablinkslen, Itablinkscap uint64 @@ -1765,7 +1748,7 @@ type moduledata_1_20_64 struct { Pkghashes, Pkghasheslen, Pkghashescap uint64 } -func (md moduledata_1_20_64) toModuledata() moduledata { +func (md moduledata_1_8_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -1787,50 +1770,36 @@ func (md moduledata_1_20_64) toModuledata() moduledata { FuncTabLen: md.Ftablen, PCLNTabAddr: md.Pclntable, PCLNTabLen: md.Pclntablelen, - GoFuncVal: md.Gofunc, } } -type moduledata_1_21_32 struct { - PcHeader uint32 - Funcnametab, Funcnametablen, Funcnametabcap uint32 - Cutab, Cutablen, Cutabcap uint32 - Filetab, Filetablen, Filetabcap uint32 - Pctab, Pctablen, Pctabcap uint32 - Pclntable, Pclntablelen, Pclntablecap uint32 - Ftab, Ftablen, Ftabcap uint32 - Findfunctab uint32 - Minpc uint32 - Maxpc uint32 - Text uint32 - Etext uint32 - Noptrdata uint32 - Enoptrdata uint32 - Data uint32 - Edata uint32 - Bss uint32 - Ebss uint32 - Noptrbss uint32 - Enoptrbss uint32 - Covctrs uint32 - Ecovctrs uint32 - End uint32 - Gcdata uint32 - Gcbss uint32 - Types uint32 - Etypes uint32 - Rodata uint32 - Gofunc uint32 - Textsectmap, Textsectmaplen, Textsectmapcap uint32 - Typelinks, Typelinkslen, Typelinkscap uint32 - Itablinks, Itablinkslen, Itablinkscap uint32 - Ptab, Ptablen, Ptabcap uint32 - Pluginpath, Pluginpathlen uint32 - Pkghashes, Pkghasheslen, Pkghashescap uint32 - Inittasks, Inittaskslen, Inittaskscap uint32 +type moduledata_1_7_32 struct { + Pclntable, Pclntablelen, Pclntablecap uint32 + Ftab, Ftablen, Ftabcap uint32 + Filetab, Filetablen, Filetabcap uint32 + Findfunctab uint32 + Minpc uint32 + Maxpc uint32 + Text uint32 + Etext uint32 + Noptrdata uint32 + Enoptrdata uint32 + Data uint32 + Edata uint32 + Bss uint32 + Ebss uint32 + Noptrbss uint32 + Enoptrbss uint32 + End uint32 + Gcdata uint32 + Gcbss uint32 + Types uint32 + Etypes uint32 + Typelinks, Typelinkslen, Typelinkscap uint32 + Itablinks, Itablinkslen, Itablinkscap uint32 } -func (md moduledata_1_21_32) toModuledata() moduledata { +func (md moduledata_1_7_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -1852,50 +1821,36 @@ func (md moduledata_1_21_32) toModuledata() moduledata { FuncTabLen: uint64(md.Ftablen), PCLNTabAddr: uint64(md.Pclntable), PCLNTabLen: uint64(md.Pclntablelen), - GoFuncVal: uint64(md.Gofunc), } } -type moduledata_1_21_64 struct { - PcHeader uint64 - Funcnametab, Funcnametablen, Funcnametabcap uint64 - Cutab, Cutablen, Cutabcap uint64 - Filetab, Filetablen, Filetabcap uint64 - Pctab, Pctablen, Pctabcap uint64 - Pclntable, Pclntablelen, Pclntablecap uint64 - Ftab, Ftablen, Ftabcap uint64 - Findfunctab uint64 - Minpc uint64 - Maxpc uint64 - Text uint64 - Etext uint64 - Noptrdata uint64 - Enoptrdata uint64 - Data uint64 - Edata uint64 - Bss uint64 - Ebss uint64 - Noptrbss uint64 - Enoptrbss uint64 - Covctrs uint64 - Ecovctrs uint64 - End uint64 - Gcdata uint64 - Gcbss uint64 - Types uint64 - Etypes uint64 - Rodata uint64 - Gofunc uint64 - Textsectmap, Textsectmaplen, Textsectmapcap uint64 - Typelinks, Typelinkslen, Typelinkscap uint64 - Itablinks, Itablinkslen, Itablinkscap uint64 - Ptab, Ptablen, Ptabcap uint64 - Pluginpath, Pluginpathlen uint64 - Pkghashes, Pkghasheslen, Pkghashescap uint64 - Inittasks, Inittaskslen, Inittaskscap uint64 +type moduledata_1_7_64 struct { + Pclntable, Pclntablelen, Pclntablecap uint64 + Ftab, Ftablen, Ftabcap uint64 + Filetab, Filetablen, Filetabcap uint64 + Findfunctab uint64 + Minpc uint64 + Maxpc uint64 + Text uint64 + Etext uint64 + Noptrdata uint64 + Enoptrdata uint64 + Data uint64 + Edata uint64 + Bss uint64 + Ebss uint64 + Noptrbss uint64 + Enoptrbss uint64 + End uint64 + Gcdata uint64 + Gcbss uint64 + Types uint64 + Etypes uint64 + Typelinks, Typelinkslen, Typelinkscap uint64 + Itablinks, Itablinkslen, Itablinkscap uint64 } -func (md moduledata_1_21_64) toModuledata() moduledata { +func (md moduledata_1_7_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -1917,50 +1872,33 @@ func (md moduledata_1_21_64) toModuledata() moduledata { FuncTabLen: md.Ftablen, PCLNTabAddr: md.Pclntable, PCLNTabLen: md.Pclntablelen, - GoFuncVal: md.Gofunc, } } -type moduledata_1_22_32 struct { - PcHeader uint32 - Funcnametab, Funcnametablen, Funcnametabcap uint32 - Cutab, Cutablen, Cutabcap uint32 - Filetab, Filetablen, Filetabcap uint32 - Pctab, Pctablen, Pctabcap uint32 - Pclntable, Pclntablelen, Pclntablecap uint32 - Ftab, Ftablen, Ftabcap uint32 - Findfunctab uint32 - Minpc uint32 - Maxpc uint32 - Text uint32 - Etext uint32 - Noptrdata uint32 - Enoptrdata uint32 - Data uint32 - Edata uint32 - Bss uint32 - Ebss uint32 - Noptrbss uint32 - Enoptrbss uint32 - Covctrs uint32 - Ecovctrs uint32 - End uint32 - Gcdata uint32 - Gcbss uint32 - Types uint32 - Etypes uint32 - Rodata uint32 - Gofunc uint32 - Textsectmap, Textsectmaplen, Textsectmapcap uint32 - Typelinks, Typelinkslen, Typelinkscap uint32 - Itablinks, Itablinkslen, Itablinkscap uint32 - Ptab, Ptablen, Ptabcap uint32 - Pluginpath, Pluginpathlen uint32 - Pkghashes, Pkghasheslen, Pkghashescap uint32 - Inittasks, Inittaskslen, Inittaskscap uint32 +type moduledata_1_6_32 struct { + Pclntable, Pclntablelen, Pclntablecap uint32 + Ftab, Ftablen, Ftabcap uint32 + Filetab, Filetablen, Filetabcap uint32 + Findfunctab uint32 + Minpc uint32 + Maxpc uint32 + Text uint32 + Etext uint32 + Noptrdata uint32 + Enoptrdata uint32 + Data uint32 + Edata uint32 + Bss uint32 + Ebss uint32 + Noptrbss uint32 + Enoptrbss uint32 + End uint32 + Gcdata uint32 + Gcbss uint32 + Typelinks, Typelinkslen, Typelinkscap uint32 } -func (md moduledata_1_22_32) toModuledata() moduledata { +func (md moduledata_1_6_32) toModuledata() moduledata { return moduledata{ TextAddr: uint64(md.Text), TextLen: uint64(md.Etext - md.Text), @@ -1972,60 +1910,127 @@ func (md moduledata_1_22_32) toModuledata() moduledata { BssLen: uint64(md.Ebss - md.Bss), NoPtrBssAddr: uint64(md.Noptrbss), NoPtrBssLen: uint64(md.Enoptrbss - md.Noptrbss), - TypesAddr: uint64(md.Types), - TypesLen: uint64(md.Etypes - md.Types), TypelinkAddr: uint64(md.Typelinks), TypelinkLen: uint64(md.Typelinkslen), - ITabLinkAddr: uint64(md.Itablinks), - ITabLinkLen: uint64(md.Itablinkslen), FuncTabAddr: uint64(md.Ftab), FuncTabLen: uint64(md.Ftablen), PCLNTabAddr: uint64(md.Pclntable), PCLNTabLen: uint64(md.Pclntablelen), - GoFuncVal: uint64(md.Gofunc), } } -type moduledata_1_22_64 struct { - PcHeader uint64 - Funcnametab, Funcnametablen, Funcnametabcap uint64 - Cutab, Cutablen, Cutabcap uint64 - Filetab, Filetablen, Filetabcap uint64 - Pctab, Pctablen, Pctabcap uint64 - Pclntable, Pclntablelen, Pclntablecap uint64 - Ftab, Ftablen, Ftabcap uint64 - Findfunctab uint64 - Minpc uint64 - Maxpc uint64 - Text uint64 - Etext uint64 - Noptrdata uint64 - Enoptrdata uint64 - Data uint64 - Edata uint64 - Bss uint64 - Ebss uint64 - Noptrbss uint64 - Enoptrbss uint64 - Covctrs uint64 - Ecovctrs uint64 - End uint64 - Gcdata uint64 - Gcbss uint64 - Types uint64 - Etypes uint64 - Rodata uint64 - Gofunc uint64 - Textsectmap, Textsectmaplen, Textsectmapcap uint64 - Typelinks, Typelinkslen, Typelinkscap uint64 - Itablinks, Itablinkslen, Itablinkscap uint64 - Ptab, Ptablen, Ptabcap uint64 - Pluginpath, Pluginpathlen uint64 - Pkghashes, Pkghasheslen, Pkghashescap uint64 - Inittasks, Inittaskslen, Inittaskscap uint64 +type moduledata_1_6_64 struct { + Pclntable, Pclntablelen, Pclntablecap uint64 + Ftab, Ftablen, Ftabcap uint64 + Filetab, Filetablen, Filetabcap uint64 + Findfunctab uint64 + Minpc uint64 + Maxpc uint64 + Text uint64 + Etext uint64 + Noptrdata uint64 + Enoptrdata uint64 + Data uint64 + Edata uint64 + Bss uint64 + Ebss uint64 + Noptrbss uint64 + Enoptrbss uint64 + End uint64 + Gcdata uint64 + Gcbss uint64 + Typelinks, Typelinkslen, Typelinkscap uint64 } -func (md moduledata_1_22_64) toModuledata() moduledata { +func (md moduledata_1_6_64) toModuledata() moduledata { + return moduledata{ + TextAddr: md.Text, + TextLen: md.Etext - md.Text, + NoPtrDataAddr: md.Noptrdata, + NoPtrDataLen: md.Enoptrdata - md.Noptrdata, + DataAddr: md.Data, + DataLen: md.Edata - md.Data, + BssAddr: md.Bss, + BssLen: md.Ebss - md.Bss, + NoPtrBssAddr: md.Noptrbss, + NoPtrBssLen: md.Enoptrbss - md.Noptrbss, + TypelinkAddr: md.Typelinks, + TypelinkLen: md.Typelinkslen, + FuncTabAddr: md.Ftab, + FuncTabLen: md.Ftablen, + PCLNTabAddr: md.Pclntable, + PCLNTabLen: md.Pclntablelen, + } +} + +type moduledata_1_5_32 struct { + Pclntable, Pclntablelen, Pclntablecap uint32 + Ftab, Ftablen, Ftabcap uint32 + Filetab, Filetablen, Filetabcap uint32 + Findfunctab uint32 + Minpc uint32 + Maxpc uint32 + Text uint32 + Etext uint32 + Noptrdata uint32 + Enoptrdata uint32 + Data uint32 + Edata uint32 + Bss uint32 + Ebss uint32 + Noptrbss uint32 + Enoptrbss uint32 + End uint32 + Gcdata uint32 + Gcbss uint32 + Typelinks, Typelinkslen, Typelinkscap uint32 +} + +func (md moduledata_1_5_32) toModuledata() moduledata { + return moduledata{ + TextAddr: uint64(md.Text), + TextLen: uint64(md.Etext - md.Text), + NoPtrDataAddr: uint64(md.Noptrdata), + NoPtrDataLen: uint64(md.Enoptrdata - md.Noptrdata), + DataAddr: uint64(md.Data), + DataLen: uint64(md.Edata - md.Data), + BssAddr: uint64(md.Bss), + BssLen: uint64(md.Ebss - md.Bss), + NoPtrBssAddr: uint64(md.Noptrbss), + NoPtrBssLen: uint64(md.Enoptrbss - md.Noptrbss), + TypelinkAddr: uint64(md.Typelinks), + TypelinkLen: uint64(md.Typelinkslen), + FuncTabAddr: uint64(md.Ftab), + FuncTabLen: uint64(md.Ftablen), + PCLNTabAddr: uint64(md.Pclntable), + PCLNTabLen: uint64(md.Pclntablelen), + } +} + +type moduledata_1_5_64 struct { + Pclntable, Pclntablelen, Pclntablecap uint64 + Ftab, Ftablen, Ftabcap uint64 + Filetab, Filetablen, Filetabcap uint64 + Findfunctab uint64 + Minpc uint64 + Maxpc uint64 + Text uint64 + Etext uint64 + Noptrdata uint64 + Enoptrdata uint64 + Data uint64 + Edata uint64 + Bss uint64 + Ebss uint64 + Noptrbss uint64 + Enoptrbss uint64 + End uint64 + Gcdata uint64 + Gcbss uint64 + Typelinks, Typelinkslen, Typelinkscap uint64 +} + +func (md moduledata_1_5_64) toModuledata() moduledata { return moduledata{ TextAddr: md.Text, TextLen: md.Etext - md.Text, @@ -2037,95 +2042,139 @@ func (md moduledata_1_22_64) toModuledata() moduledata { BssLen: md.Ebss - md.Bss, NoPtrBssAddr: md.Noptrbss, NoPtrBssLen: md.Enoptrbss - md.Noptrbss, - TypesAddr: md.Types, - TypesLen: md.Etypes - md.Types, TypelinkAddr: md.Typelinks, TypelinkLen: md.Typelinkslen, - ITabLinkAddr: md.Itablinks, - ITabLinkLen: md.Itablinkslen, FuncTabAddr: md.Ftab, FuncTabLen: md.Ftablen, PCLNTabAddr: md.Pclntable, PCLNTabLen: md.Pclntablelen, - GoFuncVal: md.Gofunc, } } func selectModuleData(v int, bits int) (modulable, error) { switch { - case v == 5 && bits == 32: - return &moduledata_1_5_32{}, nil - case v == 5 && bits == 64: - return &moduledata_1_5_64{}, nil - case v == 6 && bits == 32: - return &moduledata_1_6_32{}, nil - case v == 6 && bits == 64: - return &moduledata_1_6_64{}, nil - case v == 7 && bits == 32: - return &moduledata_1_7_32{}, nil - case v == 7 && bits == 64: - return &moduledata_1_7_64{}, nil - case v == 8 && bits == 32: - return &moduledata_1_8_32{}, nil - case v == 8 && bits == 64: - return &moduledata_1_8_64{}, nil - case v == 9 && bits == 32: - return &moduledata_1_9_32{}, nil - case v == 9 && bits == 64: - return &moduledata_1_9_64{}, nil - case v == 10 && bits == 32: - return &moduledata_1_10_32{}, nil - case v == 10 && bits == 64: - return &moduledata_1_10_64{}, nil - case v == 11 && bits == 32: - return &moduledata_1_11_32{}, nil - case v == 11 && bits == 64: - return &moduledata_1_11_64{}, nil - case v == 12 && bits == 32: - return &moduledata_1_12_32{}, nil - case v == 12 && bits == 64: - return &moduledata_1_12_64{}, nil - case v == 13 && bits == 32: - return &moduledata_1_13_32{}, nil - case v == 13 && bits == 64: - return &moduledata_1_13_64{}, nil - case v == 14 && bits == 32: - return &moduledata_1_14_32{}, nil - case v == 14 && bits == 64: - return &moduledata_1_14_64{}, nil - case v == 15 && bits == 32: - return &moduledata_1_15_32{}, nil - case v == 15 && bits == 64: - return &moduledata_1_15_64{}, nil - case v == 16 && bits == 32: - return &moduledata_1_16_32{}, nil - case v == 16 && bits == 64: - return &moduledata_1_16_64{}, nil - case v == 17 && bits == 32: - return &moduledata_1_17_32{}, nil - case v == 17 && bits == 64: - return &moduledata_1_17_64{}, nil - case v == 18 && bits == 32: - return &moduledata_1_18_32{}, nil - case v == 18 && bits == 64: - return &moduledata_1_18_64{}, nil - case v == 19 && bits == 32: - return &moduledata_1_19_32{}, nil - case v == 19 && bits == 64: - return &moduledata_1_19_64{}, nil - case v == 20 && bits == 32: - return &moduledata_1_20_32{}, nil - case v == 20 && bits == 64: - return &moduledata_1_20_64{}, nil - case v == 21 && bits == 32: - return &moduledata_1_21_32{}, nil - case v == 21 && bits == 64: - return &moduledata_1_21_64{}, nil case v == 22 && bits == 32: return &moduledata_1_22_32{}, nil case v == 22 && bits == 64: return &moduledata_1_22_64{}, nil + case v == 21 && bits == 32: + return &moduledata_1_21_32{}, nil + case v == 21 && bits == 64: + return &moduledata_1_21_64{}, nil + case v == 20 && bits == 32: + return &moduledata_1_20_32{}, nil + case v == 20 && bits == 64: + return &moduledata_1_20_64{}, nil + case v == 19 && bits == 32: + return &moduledata_1_19_32{}, nil + case v == 19 && bits == 64: + return &moduledata_1_19_64{}, nil + case v == 18 && bits == 32: + return &moduledata_1_18_32{}, nil + case v == 18 && bits == 64: + return &moduledata_1_18_64{}, nil + case v == 17 && bits == 32: + return &moduledata_1_17_32{}, nil + case v == 17 && bits == 64: + return &moduledata_1_17_64{}, nil + case v == 16 && bits == 32: + return &moduledata_1_16_32{}, nil + case v == 16 && bits == 64: + return &moduledata_1_16_64{}, nil + case v == 15 && bits == 32: + return &moduledata_1_15_32{}, nil + case v == 15 && bits == 64: + return &moduledata_1_15_64{}, nil + case v == 14 && bits == 32: + return &moduledata_1_14_32{}, nil + case v == 14 && bits == 64: + return &moduledata_1_14_64{}, nil + case v == 13 && bits == 32: + return &moduledata_1_13_32{}, nil + case v == 13 && bits == 64: + return &moduledata_1_13_64{}, nil + case v == 12 && bits == 32: + return &moduledata_1_12_32{}, nil + case v == 12 && bits == 64: + return &moduledata_1_12_64{}, nil + case v == 11 && bits == 32: + return &moduledata_1_11_32{}, nil + case v == 11 && bits == 64: + return &moduledata_1_11_64{}, nil + case v == 10 && bits == 32: + return &moduledata_1_10_32{}, nil + case v == 10 && bits == 64: + return &moduledata_1_10_64{}, nil + case v == 9 && bits == 32: + return &moduledata_1_9_32{}, nil + case v == 9 && bits == 64: + return &moduledata_1_9_64{}, nil + case v == 8 && bits == 32: + return &moduledata_1_8_32{}, nil + case v == 8 && bits == 64: + return &moduledata_1_8_64{}, nil + case v == 7 && bits == 32: + return &moduledata_1_7_32{}, nil + case v == 7 && bits == 64: + return &moduledata_1_7_64{}, nil + case v == 6 && bits == 32: + return &moduledata_1_6_32{}, nil + case v == 6 && bits == 64: + return &moduledata_1_6_64{}, nil + case v == 5 && bits == 32: + return &moduledata_1_5_32{}, nil + case v == 5 && bits == 64: + return &moduledata_1_5_64{}, nil default: return nil, fmt.Errorf("unsupported version %d and bits %d", v, bits) } } + +func getModuleDataList(bits int) ([]modulable, error) { + if bits != 32 && bits != 64 { + return nil, fmt.Errorf("unsupported bits %d", bits) + } + if bits == 32 { + return []modulable{ + &moduledata_1_22_32{}, + &moduledata_1_21_32{}, + &moduledata_1_20_32{}, + &moduledata_1_19_32{}, + &moduledata_1_18_32{}, + &moduledata_1_17_32{}, + &moduledata_1_16_32{}, + &moduledata_1_15_32{}, + &moduledata_1_14_32{}, + &moduledata_1_13_32{}, + &moduledata_1_12_32{}, + &moduledata_1_11_32{}, + &moduledata_1_10_32{}, + &moduledata_1_9_32{}, + &moduledata_1_8_32{}, + &moduledata_1_7_32{}, + &moduledata_1_6_32{}, + &moduledata_1_5_32{}, + }, nil + } else { + return []modulable{ + &moduledata_1_22_64{}, + &moduledata_1_21_64{}, + &moduledata_1_20_64{}, + &moduledata_1_19_64{}, + &moduledata_1_18_64{}, + &moduledata_1_17_64{}, + &moduledata_1_16_64{}, + &moduledata_1_15_64{}, + &moduledata_1_14_64{}, + &moduledata_1_13_64{}, + &moduledata_1_12_64{}, + &moduledata_1_11_64{}, + &moduledata_1_10_64{}, + &moduledata_1_9_64{}, + &moduledata_1_8_64{}, + &moduledata_1_7_64{}, + &moduledata_1_6_64{}, + &moduledata_1_5_64{}, + }, nil + } +} diff --git a/pclntab.go b/pclntab.go index 900f1e3..7baf409 100644 --- a/pclntab.go +++ b/pclntab.go @@ -19,56 +19,49 @@ package gore import ( "bytes" - "debug/pe" + "encoding/binary" + "sync" ) -// pclntab12magic is the magic bytes used for binaries compiled with Go -// prior to 1.16 -var pclntab12magic = []byte{0xfb, 0xff, 0xff, 0xff, 0x0, 0x0} +// keep sync with debug/gosym/pclntab.go +const ( + gopclntab12magic uint32 = 0xfffffffb + gopclntab116magic uint32 = 0xfffffffa + gopclntab118magic uint32 = 0xfffffff0 + gopclntab120magic uint32 = 0xfffffff1 +) -// pclntab116magic is the magic bytes used for binaries compiled with -// Go 1.16 and Go 1.17. -var pclntab116magic = []byte{0xfa, 0xff, 0xff, 0xff, 0x0, 0x0} +// if the target relies on a brute force search, +// use this cache the result +type pclntabOnce struct { + *sync.Once + pclntab []byte + start uint64 + err error +} -// pclntab118magic is the magic bytes used for binaries compiled with -// Go 1.18 and Go 1.19. -var pclntab118magic = []byte{0xf0, 0xff, 0xff, 0xff, 0x0, 0x0} +func newPclnTabOnce() *pclntabOnce { + return &pclntabOnce{Once: &sync.Once{}} +} -// pclntab120magic is the magic bytes used for binaries compiled with -// Go 1.20 and onwards. -var pclntab120magic = []byte{0xf1, 0xff, 0xff, 0xff, 0x0, 0x0} +func (o *pclntabOnce) load(loader func() (uint64, []byte, error)) (uint64, []byte, error) { + o.Do(func() { + o.start, o.pclntab, o.err = loader() + }) + return o.start, o.pclntab, o.err -// searchFileForPCLNTab will search the .rdata and .text section for the -// PCLN table. Note!! The address returned by this function needs to be -// adjusted by adding the image base address!!! -func searchFileForPCLNTab(f *pe.File) (uint32, []byte, error) { - for _, v := range []string{".rdata", ".text"} { - sec := f.Section(v) - if sec == nil { - continue - } - secData, err := sec.Data() - if err != nil { - continue - } - tab, err := searchSectionForTab(secData) - if err == ErrNoPCLNTab { - continue - } - // TODO: Switch to returning a uint64 instead. - addr := sec.VirtualAddress + uint32(len(secData)-len(tab)) - return addr, tab, err - } - return 0, []byte{}, ErrNoPCLNTab } // searchSectionForTab looks for the PCLN table within the section. -func searchSectionForTab(secData []byte) ([]byte, error) { +func searchSectionForTab(secData []byte, order binary.ByteOrder) ([]byte, error) { // First check for the current magic used. If this fails, it could be // an older version. So check for the old header. -MAGIC_LOOP: - for _, magic := range [][]byte{pclntab120magic, pclntab118magic, pclntab116magic, pclntab12magic} { - off := bytes.LastIndex(secData, magic) +MagicLoop: + for _, magic := range []uint32{gopclntab120magic, gopclntab118magic, gopclntab116magic, gopclntab12magic} { + bMagic := make([]byte, 6) // 4 bytes for the magic, 2 bytes for padding. + order.PutUint32(bMagic, magic) + + off := bytes.LastIndex(secData, bMagic) if off == -1 { continue // Try other magic. } @@ -80,9 +73,9 @@ MAGIC_LOOP: (buf[7] != 4 && buf[7] != 8) { // pointer size // Header doesn't match. if off-1 <= 0 { - continue MAGIC_LOOP + continue MagicLoop } - off = bytes.LastIndex(secData[:off-1], magic) + off = bytes.LastIndex(secData[:off-1], bMagic) continue } // Header match diff --git a/pe.go b/pe.go index 6a58d16..fe89645 100644 --- a/pe.go +++ b/pe.go @@ -19,11 +19,13 @@ package gore import ( "debug/dwarf" - "debug/gosym" "debug/pe" "encoding/binary" + "errors" "fmt" "os" + "slices" + "sort" ) func openPE(fp string) (peF *peFile, err error) { @@ -47,17 +49,98 @@ func openPE(fp string) (peF *peFile, err error) { err = fmt.Errorf("error when parsing the PE file: %w", err) return } - peF = &peFile{file: f, osFile: osFile} + + imageBase := uint64(0) + + switch hdr := f.OptionalHeader.(type) { + case *pe.OptionalHeader32: + imageBase = uint64(hdr.ImageBase) + case *pe.OptionalHeader64: + imageBase = hdr.ImageBase + default: + err = errors.New("unknown optional header type") + return + } + + peF = &peFile{ + file: f, + osFile: osFile, + imageBase: imageBase, + pcln: newPclnTabOnce(), + symtab: newSymbolTableOnce(), + } return } var _ fileHandler = (*peFile)(nil) type peFile struct { - file *pe.File - osFile *os.File - pclntabAddr uint64 - imageBase uint64 + file *pe.File + osFile *os.File + imageBase uint64 + pcln *pclntabOnce + symtab *symbolTableOnce +} + +func (p *peFile) initSymTab() error { + p.symtab.Do(func() { + var addrs []uint64 + + var syms []symbol + for _, s := range p.file.Symbols { + const ( + NUndef = 0 // An undefined (extern) symbol + NAbs = -1 // An absolute symbol (e_value is a constant, not an address) + NDebug = -2 // A debugging symbol + ) + sym := symbol{Name: s.Name, Value: uint64(s.Value), Size: 0} + switch s.SectionNumber { + case NUndef, NAbs, NDebug: // do nothing + default: + if s.SectionNumber < 0 || len(p.file.Sections) < int(s.SectionNumber) { + p.symtab.err = fmt.Errorf("invalid section number in symbol table") + return + } + sect := p.file.Sections[s.SectionNumber-1] + sym.Value += p.imageBase + uint64(sect.VirtualAddress) + } + syms = append(syms, sym) + addrs = append(addrs, sym.Value) + } + + slices.Sort(addrs) + for i := range syms { + j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Value }) + if j < len(addrs) { + syms[i].Size = addrs[j] - syms[i].Value + } + } + + for _, sym := range syms { + p.symtab.table[sym.Name] = sym + } + }) + return p.symtab.err +} + +func (p *peFile) hasSymbolTable() (bool, error) { + err := p.initSymTab() + if err != nil { + return false, err + } + return len(p.symtab.table) > 0, nil +} + +func (p *peFile) getSymbol(name string) (uint64, uint64, error) { + err := p.initSymTab() + if err != nil { + return 0, 0, err + } + sym, ok := p.symtab.table[name] + if !ok { + return 0, 0, ErrSymbolNotFound + } + return sym.Value, sym.Size, nil } func (p *peFile) getParsedFile() any { @@ -68,14 +151,28 @@ func (p *peFile) getFile() *os.File { return p.osFile } -func (p *peFile) getPCLNTab() (*gosym.Table, error) { - addr, pclndat, err := searchFileForPCLNTab(p.file) - if err != nil { - return nil, err +// searchFileForPCLNTab will search the .rdata section for the +// PCLN table. +func (p *peFile) searchForPCLNTab() (uint32, []byte, error) { + for _, s := range []string{".rdata", ".text"} { + sec := p.file.Section(s) + if sec == nil { + continue + } + secData, err := sec.Data() + if err != nil { + return 0, nil, err + } + + tab, err := searchSectionForTab(secData, p.getFileInfo().ByteOrder) + if err != nil { + continue + } + + addr := sec.VirtualAddress + uint32(len(secData)-len(tab)) + return addr, tab, err } - pcln := gosym.NewLineTable(pclndat, uint64(p.file.Section(".text").VirtualAddress)+p.imageBase) - p.pclntabAddr = uint64(addr) + p.imageBase - return gosym.NewTable(make([]byte, 0), pcln) + return 0, nil, ErrNoPCLNTab } func (p *peFile) Close() error { @@ -108,8 +205,12 @@ func (p *peFile) moduledataSection() string { } func (p *peFile) getPCLNTABData() (uint64, []byte, error) { - b, d, e := searchFileForPCLNTab(p.file) - return p.imageBase + uint64(b), d, e + return p.pcln.load(p.getPCLNTABDataImpl) +} + +func (p *peFile) getPCLNTABDataImpl() (uint64, []byte, error) { + start, data, err := p.searchForPCLNTab() + return p.imageBase + uint64(start), data, err } func (p *peFile) getSectionDataFromAddress(address uint64) (uint64, []byte, error) { @@ -140,13 +241,9 @@ func (p *peFile) getFileInfo() *FileInfo { fi := &FileInfo{ByteOrder: binary.LittleEndian, OS: "windows"} if p.file.Machine == pe.IMAGE_FILE_MACHINE_I386 { fi.WordSize = intSize32 - optHdr := p.file.OptionalHeader.(*pe.OptionalHeader32) - p.imageBase = uint64(optHdr.ImageBase) fi.Arch = Arch386 } else { fi.WordSize = intSize64 - optHdr := p.file.OptionalHeader.(*pe.OptionalHeader64) - p.imageBase = optHdr.ImageBase fi.Arch = ArchAMD64 } return fi diff --git a/slow_test.go b/slow_test.go index 4510307..3df5e9d 100644 --- a/slow_test.go +++ b/slow_test.go @@ -15,7 +15,6 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . //go:build slow_test -// +build slow_test package gore @@ -47,254 +46,205 @@ var dynResources = []struct { var dynResourceFiles *testFiles type testFiles struct { - files map[string]string - filesMu sync.RWMutex + files sync.Map } func (f *testFiles) get(os, arch string, pie, stripped bool) string { - f.filesMu.Lock() - defer f.filesMu.Unlock() + name := os + "-" + arch if pie { - return f.files[os+arch+"-pie"] + name += "-pie" } if !stripped { - return f.files[os+arch+"-nostrip"] + name += "-nostrip" + } + exe, ok := f.files.Load(name) + if !ok { + return "" + } + return exe.(string) +} + +// pass nil to check means all combinations +func getMatrix(t *testing.T, checkPie, checkStrip *bool, prefix string, cb func(*testing.T, string)) { + t.Helper() + for _, r := range dynResources { + var pieCases []bool + if checkPie != nil { + pieCases = append(pieCases, *checkPie) + } else { + pieCases = append(pieCases, true, false) + } + for _, pie := range pieCases { + var strippedCases []bool + if checkStrip != nil { + strippedCases = append(strippedCases, *checkStrip) + } else { + strippedCases = append(strippedCases, true, false) + } + for _, stripped := range strippedCases { + exe := dynResourceFiles.get(r.os, r.arch, pie, stripped) + name := r.os + "-" + r.arch + if pie { + name += "-pie" + } + if !stripped { + name += "-nostrip" + } + t.Run(prefix+"-"+name, func(tt *testing.T) { + tt.Parallel() + if exe == "" { + tt.Skip("no executable available") + } + cb(tt, exe) + }) + } + } + } - return f.files[os+arch] } func TestMain(m *testing.M) { fmt.Println("Creating test resources, this can take some time...") var tmpDirs []string - fs := make(map[string]string) - for _, r := range dynResources { - fmt.Printf("Building resource file for %s_%s\n", r.os, r.arch) - exe, dir := buildTestResource(testresourcesrc, r.os, r.arch, false, true) - tmpDirs = append(tmpDirs, dir) - fs[r.os+r.arch] = exe - - // Build PIE version of the file. Not all host systems, particular macOS, appears to be able - // to compile a PIE build of linux-386. In this case, we skip this combination. - if !(r.arch == "386" && r.os == "linux") { - exe, dir = buildTestResource(testresourcesrc, r.os, r.arch, true, true) - tmpDirs = append(tmpDirs, dir) - fs[r.os+r.arch+"-pie"] = exe + + resultChan := make(chan buildResult) + wg := &sync.WaitGroup{} + + dynResourceFiles = &testFiles{files: sync.Map{}} + + go func() { + for r := range resultChan { + tmpDirs = append(tmpDirs, r.dir) + name := r.os + "-" + r.arch + if r.pie { + name += "-pie" + } + if !r.strip { + name += "-nostrip" + } + dynResourceFiles.files.Store(name, r.exe) } + }() - // build unstripped binary; needs separate source file with reference to GOROOT - // for test trying to access it to pass - exe, dir = buildTestResource(nostripSrc, r.os, r.arch, false, false) - tmpDirs = append(tmpDirs, dir) - fs[r.os+r.arch+"-nostrip"] = exe + for _, r := range dynResources { + fmt.Printf("Building resource file for %s_%s\n", r.os, r.arch) + for _, pie := range []bool{false, true} { + for _, stripped := range []bool{false, true} { + if pie && r.arch == "386" && r.os == "linux" { + // seems impossible + continue + } + wg.Add(1) + go buildTestResource(testresourcesrc, r.os, r.arch, pie, stripped, wg, resultChan) + } + } } - dynResourceFiles = &testFiles{files: fs} + + wg.Wait() + close(resultChan) fmt.Println("Launching tests") code := m.Run() fmt.Println("Clean up test resources") + for _, d := range tmpDirs { os.RemoveAll(d) } + os.Exit(code) } func TestOpenAndCloseFile(t *testing.T) { - for _, test := range dynResources { - t.Run("open_"+test.os+"-"+test.arch, func(t *testing.T) { - assert := assert.New(t) - exe := dynResourceFiles.get(test.os, test.arch, false, true) - - f, err := Open(exe) - assert.NoError(err) - assert.NotNil(f) - assert.NoError(f.Close()) - }) - - t.Run("open_"+test.os+"-"+test.arch+"-pie", func(t *testing.T) { - assert := assert.New(t) - exe := dynResourceFiles.get(test.os, test.arch, true, true) - if exe == "" { - t.Skip("no PIE available") - } - - f, err := Open(exe) - assert.NoError(err) - assert.NotNil(f) - assert.NoError(f.Close()) - }) - } + getMatrix(t, nil, nil, "open", func(t *testing.T, exe string) { + a := assert.New(t) + + f, err := Open(exe) + a.NoError(err) + a.NotNil(f) + a.NoError(f.Close()) + }) } func TestGetPackages(t *testing.T) { - for _, test := range dynResources { - t.Run("open_"+test.os+"-"+test.arch, func(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - exe := dynResourceFiles.get(test.os, test.arch, false, true) - if exe == "" { - t.Skip("no PIE available") - } - - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - std, err := f.GetSTDLib() - assert.NoError(err) - assert.NotEmpty(std, "Should have a list of standard library packages.") - - _, err = f.GetGeneratedPackages() - assert.NoError(err) - // XXX: This check appears to be unstable. Sometimes files for unknown reason. - // assert.NotEmpty(gen, "Should have a list of generated packages.") - - ven, err := f.GetVendors() - assert.NoError(err) - assert.Empty(ven, "Should not have a list of vendor packages.") - - _, err = f.GetUnknown() - assert.NoError(err) - // XXX: This check appears to be unstable. Sometimes files for unknown reason. - // assert.Empty(unk, "Should not have a list of unknown packages") - - pkgs, err := f.GetPackages() - assert.NoError(err) - - var mainpkg *Package - for _, p := range pkgs { - if p.Name == "main" { - mainpkg = p - break - } + getMatrix(t, nil, nil, "getPackages", func(t *testing.T, exe string) { + a := assert.New(t) + r := require.New(t) + + f, err := Open(exe) + r.NoError(err) + r.NotNil(f) + defer f.Close() + + std, err := f.GetSTDLib() + a.NoError(err) + a.NotEmpty(std, "Should have a list of standard library packages.") + + _, err = f.GetGeneratedPackages() + a.NoError(err) + // XXX: This check appears to be unstable. Sometimes files for unknown reason. + // assert.NotEmpty(gen, "Should have a list of generated packages.") + + ven, err := f.GetVendors() + a.NoError(err) + a.Empty(ven, "Should not have a list of vendor packages.") + + _, err = f.GetUnknown() + a.NoError(err) + // XXX: This check appears to be unstable. Sometimes files for unknown reason. + // assert.Empty(unk, "Should not have a list of unknown packages") + + pkgs, err := f.GetPackages() + a.NoError(err) + + var mainpkg *Package + for _, p := range pkgs { + if p.Name == "main" { + mainpkg = p + break } + } - mp := false - gd := false - assert.NotNil(mainpkg, "Should include main package") - for _, f := range mainpkg.Functions { - if f.Name == "main" { - mp = true - } else if f.Name == "getData" { - gd = true - } else { - assert.Fail("Unexpected function") - } - } - assert.True(mp, "No main function found") - assert.True(gd, "getData function not found") - }) - - t.Run("open_"+test.os+"-"+test.arch+"-pie", func(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - exe := dynResourceFiles.get(test.os, test.arch, false, true) - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - std, err := f.GetSTDLib() - assert.NoError(err) - assert.NotEmpty(std, "Should have a list of standard library packages.") - - _, err = f.GetGeneratedPackages() - assert.NoError(err) - // XXX: This check appears to be unstable. Sometimes files for unknown reason. - // assert.NotEmpty(gen, "Should have a list of generated packages.") - - ven, err := f.GetVendors() - assert.NoError(err) - assert.Empty(ven, "Should not have a list of vendor packages.") - - _, err = f.GetUnknown() - assert.NoError(err) - // XXX: This check appears to be unstable. Sometimes files for unknown reason. - // assert.Empty(unk, "Should not have a list of unknown packages") - - pkgs, err := f.GetPackages() - assert.NoError(err) - - var mainpkg *Package - for _, p := range pkgs { - if p.Name == "main" { - mainpkg = p - break - } + mainPackageFound := false + getDataFuncFound := false + a.NotNil(mainpkg, "Should include main package") + for _, f := range mainpkg.Functions { + if f.Name == "main" { + mainPackageFound = true + } else if f.Name == "getData" { + getDataFuncFound = true + } else { + a.Fail("Unexpected function") } - - mp := false - gd := false - assert.NotNil(mainpkg, "Should include main package") - for _, f := range mainpkg.Functions { - if f.Name == "main" { - mp = true - } else if f.Name == "getData" { - gd = true - } else { - assert.Fail("Unexpected function") - } - } - assert.True(mp, "No main function found") - assert.True(gd, "getData function not found") - }) - } + } + a.True(mainPackageFound, "No main function found") + a.True(getDataFuncFound, "getData function not found") + }) } func TestGetTypesFromDynamicBuiltResources(t *testing.T) { - for _, test := range dynResources { - t.Run("open_"+test.os+"-"+test.arch, func(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - exe := dynResourceFiles.get(test.os, test.arch, false, true) - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - typs, err := f.GetTypes() - require.NoError(err) - - var stringer *GoType - for _, t := range typs { - if t.PackagePath == "runtime" && t.Name == "runtime.g" { - stringer = t - break - } - } - - assert.NotNil(stringer, "the g type from runtime not found") - }) - - t.Run("open_"+test.os+"-"+test.arch+"-pie", func(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - exe := dynResourceFiles.get(test.os, test.arch, true, true) - if exe == "" { - t.Skip(("PIE file not available")) - } - - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - typs, err := f.GetTypes() - require.NoError(err) - - var stringer *GoType - for _, t := range typs { - if t.PackagePath == "runtime" && t.Name == "runtime.g" { - stringer = t - break - } + getMatrix(t, nil, nil, "getTypes", func(t *testing.T, exe string) { + a := assert.New(t) + r := require.New(t) + f, err := Open(exe) + r.NoError(err) + r.NotNil(f) + defer f.Close() + + typs, err := f.GetTypes() + r.NoError(err) + + var stringer *GoType + for _, t := range typs { + if t.PackagePath == "runtime" && t.Name == "runtime.g" { + stringer = t + break } + } - assert.NotNil(stringer, "the g type from runtime not found") - }) - } + a.NotNil(stringer, "the g type from runtime not found") + }) } func TestGetCompilerVersion(t *testing.T) { @@ -303,177 +253,104 @@ func TestGetCompilerVersion(t *testing.T) { // If the version could not be resolved, the version is new // and the library doesn't know about it. Use the version string - // to created a new version. + // to create a new version. if expectedVersion == nil { expectedVersion = &GoVersion{Name: testVersion} } - for _, test := range dynResources { - t.Run("parsing_"+test.os+"-"+test.arch, func(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - exe := dynResourceFiles.get(test.os, test.arch, false, true) - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - // Test - version, err := f.GetCompilerVersion() - assert.NoError(err) - assert.Equal(expectedVersion, version) - }) - - t.Run("parsing_"+test.os+"-"+test.arch+"-pie", func(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - exe := dynResourceFiles.get(test.os, test.arch, true, true) - if exe == "" { - t.Skip("no PIE available") - } - - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - // Test - version, err := f.GetCompilerVersion() - assert.NoError(err) - assert.Equal(expectedVersion, version) - }) - } + getMatrix(t, nil, nil, "compiler-version", func(t *testing.T, exe string) { + a := assert.New(t) + r := require.New(t) + f, err := Open(exe) + r.NoError(err) + r.NotNil(f) + defer f.Close() + + // Test + version, err := f.GetCompilerVersion() + a.NoError(err) + a.Equal(expectedVersion, version) + }) } func TestGetBuildID(t *testing.T) { - for _, test := range dynResources { - t.Run("buildID_"+test.os+"-"+test.arch, func(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - exe := dynResourceFiles.get(test.os, test.arch, false, true) - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - assert.Equal(fixedBuildID, f.BuildID, "BuildID extracted doesn't match expected value.") - }) - - t.Run("buildID_"+test.os+"-"+test.arch+"-pie", func(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - exe := dynResourceFiles.get(test.os, test.arch, true, true) - if exe == "" { - t.Skip("no PIE available") - } - - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - assert.Equal(fixedBuildID, f.BuildID, "BuildID extracted doesn't match expected value.") - }) - } + getMatrix(t, nil, nil, "buildID", func(t *testing.T, exe string) { + a := assert.New(t) + r := require.New(t) + f, err := Open(exe) + r.NoError(err) + r.NotNil(f) + defer f.Close() + + a.Equal(fixedBuildID, f.BuildID, "BuildID extracted doesn't match expected value.") + }) } func TestSourceInfo(t *testing.T) { - for _, test := range dynResources { - t.Run("buildID_"+test.os+"-"+test.arch, func(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - exe := dynResourceFiles.get(test.os, test.arch, false, true) - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - var testFn *Function - pkgs, err := f.GetPackages() - require.NoError(err) - for _, pkg := range pkgs { - if pkg.Name != "main" { - continue - } - for _, fn := range pkg.Functions { - if fn.Name != "getData" { - continue - } - testFn = fn - break - } - } - require.NotNil(testFn) - - file, start, end := f.SourceInfo(testFn) - - assert.NotEqual(0, start) - assert.NotEqual(0, end) - assert.NotEqual("", file) - }) - - t.Run("buildID_"+test.os+"-"+test.arch+"-pie", func(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - exe := dynResourceFiles.get(test.os, test.arch, true, true) - if exe == "" { - t.Skip("no PIE available") + getMatrix(t, nil, nil, "sourceInfo", func(t *testing.T, exe string) { + a := assert.New(t) + r := require.New(t) + f, err := Open(exe) + r.NoError(err) + r.NotNil(f) + defer f.Close() + + var testFn *Function + pkgs, err := f.GetPackages() + r.NoError(err) + for _, pkg := range pkgs { + if pkg.Name != "main" { + continue } - - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - var testFn *Function - pkgs, err := f.GetPackages() - require.NoError(err) - for _, pkg := range pkgs { - if pkg.Name != "main" { + for _, fn := range pkg.Functions { + if fn.Name != "getData" { continue } - for _, fn := range pkg.Functions { - if fn.Name != "getData" { - continue - } - testFn = fn - break - } + testFn = fn + break } - require.NotNil(testFn) + } + r.NotNil(testFn) - file, start, end := f.SourceInfo(testFn) + file, start, end := f.SourceInfo(testFn) - assert.NotEqual(0, start) - assert.NotEqual(0, end) - assert.NotEqual("", file) - }) - } + a.NotEqual(0, start) + a.NotEqual(0, end) + a.NotEqual("", file) + }) } func TestDwarfString(t *testing.T) { - for _, test := range dynResources { - t.Run("dwarfString_"+test.os+"-"+test.arch, func(t *testing.T) { - require := require.New(t) - - exe := dynResourceFiles.get(test.os, test.arch, false, false) - f, err := Open(exe) - require.NoError(err) - require.NotNil(f) - defer f.Close() - - gover, ok := getBuildVersionFromDwarf(f.fh) - require.True(ok) - require.Equal(gover, runtime.Version()) - - goroot, ok := getGoRootFromDwarf(f.fh) - require.True(ok) - require.Equal(goroot, runtime.GOROOT()) - }) - } + noStrip := false + getMatrix(t, nil, &noStrip, "dwarfString", func(t *testing.T, exe string) { + r := require.New(t) + + f, err := Open(exe) + r.NoError(err) + r.NotNil(f) + defer f.Close() + + gover, ok := getBuildVersionFromDwarf(f.fh) + r.True(ok) + r.Equal(gover, runtime.Version()) + + goroot, ok := getGoRootFromDwarf(f.fh) + r.True(ok) + r.Equal(goroot, runtime.GOROOT()) + }) } -func buildTestResource(body, goos, arch string, pie, stripped bool) (string, string) { +type buildResult struct { + exe string + dir string + strip bool + pie bool + os string + arch string +} + +func buildTestResource(body, goos, arch string, pie, stripped bool, wg *sync.WaitGroup, result chan buildResult) { + defer wg.Done() goBin, err := exec.LookPath("go") if err != nil { panic("No go tool chain found: " + err.Error()) @@ -491,8 +368,8 @@ func buildTestResource(body, goos, arch string, pie, stripped bool) (string, str } exe := filepath.Join(tmpdir, "a") - if pie { - exe = exe + "-pie" + if runtime.GOOS == "windows" { + exe += ".exe" } var ldFlags string @@ -503,6 +380,9 @@ func buildTestResource(body, goos, arch string, pie, stripped bool) (string, str args := []string{"build", "-o", exe, "-ldflags", ldFlags} if pie { args = append(args, "-buildmode=pie") + } else { + // Windows use pie by default + args = append(args, "-buildmode=exe") } args = append(args, src) @@ -515,10 +395,11 @@ func buildTestResource(body, goos, arch string, pie, stripped bool) (string, str cmd.Env = append(cmd.Env, "GOCACHE="+tmpdir, "GOARCH="+arch, "GOOS="+goos, "GOPATH="+gopath, "GOTMPDIR="+gopath, "PATH="+os.Getenv("PATH")) out, err := cmd.CombinedOutput() if err != nil { - panic("building test executable failed: " + string(out)) + fmt.Printf("building test executable failed: %s\n", string(out)) + os.Exit(1) } - return exe, tmpdir + result <- buildResult{exe: exe, dir: tmpdir, strip: stripped, pie: pie, os: goos, arch: arch} } func testCompilerVersion() string { diff --git a/symbol.go b/symbol.go new file mode 100644 index 0000000..93ef123 --- /dev/null +++ b/symbol.go @@ -0,0 +1,25 @@ +package gore + +import ( + "errors" + "sync" +) + +var ErrSymbolNotFound = errors.New("symbol not found") + +// symbol A primitive representation of a symbol. +type symbol struct { + Name string + Value uint64 + Size uint64 +} + +type symbolTableOnce struct { + *sync.Once + table map[string]symbol + err error +} + +func newSymbolTableOnce() *symbolTableOnce { + return &symbolTableOnce{Once: &sync.Once{}, table: make(map[string]symbol)} +}