]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: add capturehostobjs debugging flag
authorThan McIntosh <thanm@google.com>
Tue, 1 Nov 2022 15:08:00 +0000 (11:08 -0400)
committerThan McIntosh <thanm@google.com>
Sat, 19 Nov 2022 22:39:44 +0000 (22:39 +0000)
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 <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
src/cmd/link/internal/ld/ar.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/main.go

index 1216b0c983621daa6001e04b12150494ea43f1ba..518d5ad431df24a3479070efce60d021982691ff 100644 (file)
@@ -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
index a42a66ca6e1f8e5ae914e7004263a67755f9424c..c6410b7c3970fb4957af536f28deb7e6a4bbefe5 100644 (file)
@@ -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)
+}
index c52e6e909d84761505c5078a474dc45bcc1c8c1e..0058bd4d3e2e04e3c668c5f4f599738edee5b42d 100644 (file)
@@ -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")