From: Than McIntosh Date: Tue, 1 Nov 2022 15:08:00 +0000 (-0400) Subject: cmd/link: add capturehostobjs debugging flag X-Git-Tag: go1.20rc1~141 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=bda0235466a9e2e26332f9a2646678ccdc5edaa9;p=gostls13.git cmd/link: add capturehostobjs debugging flag Add a new debugging flag "-capturehostobjs" that instructs the linker to capture copies of all object files loaded in during the host object loading portion of CGO internal linking. The intent is to make it easier to analyze the objects after the fact (as opposed to having to dig around inside archives, which can be a "find needle in haystack" exercise). Change-Id: I7023a5b72b1b899ea9b3bd6501f069d1f21bbaf0 Reviewed-on: https://go-review.googlesource.com/c/go/+/451737 Run-TryBot: Than McIntosh TryBot-Result: Gopher Robot Reviewed-by: David Chase Reviewed-by: Cherry Mui --- diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go index 1216b0c983..518d5ad431 100644 --- a/src/cmd/link/internal/ld/ar.go +++ b/src/cmd/link/internal/ld/ar.go @@ -142,6 +142,9 @@ func hostArchive(ctxt *Link, name string) { } f.MustSeek(h.off, 0) h.ld(ctxt, f, h.pkg, h.length, h.pn) + if *flagCaptureHostObjs != "" { + captureHostObj(h) + } } any = len(load) > 0 diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index a42a66ca6e..c6410b7c39 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1156,13 +1156,15 @@ func hostobjs(ctxt *Link) { if err != nil { Exitf("cannot reopen %s: %v", h.pn, err) } - f.MustSeek(h.off, 0) if h.ld == nil { Errorf(nil, "%s: unrecognized object file format", h.pn) continue } h.ld(ctxt, f, h.pkg, h.length, h.pn) + if *flagCaptureHostObjs != "" { + captureHostObj(h) + } f.Close() } } @@ -2194,8 +2196,13 @@ func hostObject(ctxt *Link, objname string, path string) { if h.ld == nil { Exitf("unrecognized object file format in %s", path) } + h.file = path + h.length = f.MustSeek(0, 2) f.MustSeek(h.off, 0) h.ld(ctxt, f, h.pkg, h.length, h.pn) + if *flagCaptureHostObjs != "" { + captureHostObj(h) + } } func checkFingerprint(lib *sym.Library, libfp goobj.FingerprintType, src string, srcfp goobj.FingerprintType) { @@ -2599,3 +2606,46 @@ func AddGotSym(target *Target, ldr *loader.Loader, syms *ArchSyms, s loader.Sym, ldr.Errorf(s, "addgotsym: unsupported binary format") } } + +var hostobjcounter int + +// captureHostObj writes out the content of a host object (pulled from +// an archive or loaded from a *.o file directly) to a directory +// specified via the linker's "-capturehostobjs" debugging flag. This +// is intended to make it easier for a developer to inspect the actual +// object feeding into "CGO internal" link step. +func captureHostObj(h *Hostobj) { + // Form paths for info file and obj file. + ofile := fmt.Sprintf("captured-obj-%d.o", hostobjcounter) + ifile := fmt.Sprintf("captured-obj-%d.txt", hostobjcounter) + hostobjcounter++ + opath := filepath.Join(*flagCaptureHostObjs, ofile) + ipath := filepath.Join(*flagCaptureHostObjs, ifile) + + // Write the info file. + info := fmt.Sprintf("pkg: %s\npn: %s\nfile: %s\noff: %d\nlen: %d\n", + h.pkg, h.pn, h.file, h.off, h.length) + if err := os.WriteFile(ipath, []byte(info), 0666); err != nil { + log.Fatalf("error writing captured host obj info %s: %v", ipath, err) + } + + readObjData := func() []byte { + inf, err := os.Open(h.file) + if err != nil { + log.Fatalf("capturing host obj: open failed on %s: %v", h.pn, err) + } + res := make([]byte, h.length) + if n, err := inf.ReadAt(res, h.off); err != nil || n != int(h.length) { + log.Fatalf("capturing host obj: readat failed on %s: %v", h.pn, err) + } + return res + } + + // Write the object file. + if err := os.WriteFile(opath, readObjData(), 0666); err != nil { + log.Fatalf("error writing captured host object %s: %v", opath, err) + } + + fmt.Fprintf(os.Stderr, "link: info: captured host object %s to %s\n", + h.file, opath) +} diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index c52e6e909d..0058bd4d3e 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -80,6 +80,8 @@ var ( flagExtldflags quoted.Flag flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive") + flagCaptureHostObjs = flag.String("capturehostobjs", "", "capture host object files loaded during internal linking to specified dir") + flagA = flag.Bool("a", false, "no-op (deprecated)") FlagC = flag.Bool("c", false, "dump call graph") FlagD = flag.Bool("d", false, "disable dynamic executable")