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 <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
Than McIntosh 2022-11-01 11:08:00 -04:00
parent 8205d83fe2
commit bda0235466
3 changed files with 56 additions and 1 deletions

View 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)
}