Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / cmd / splitdwarf / splitdwarf.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/cmd/splitdwarf/splitdwarf.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/cmd/splitdwarf/splitdwarf.go
new file mode 100644 (file)
index 0000000..44e7a7a
--- /dev/null
@@ -0,0 +1,408 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !js,!nacl,!plan9,!solaris,!windows
+
+/*
+
+Splitdwarf uncompresses and copies the DWARF segment of a Mach-O
+executable into the "dSYM" file expected by lldb and ports of gdb
+on OSX.
+
+Usage: splitdwarf osxMachoFile [ osxDsymFile ]
+
+Unless a dSYM file name is provided on the command line,
+splitdwarf will place it where the OSX tools expect it, in
+"<osxMachoFile>.dSYM/Contents/Resources/DWARF/<osxMachoFile>",
+creating directories as necessary.
+
+*/
+package main // import "golang.org/x/tools/cmd/splitdwarf"
+
+import (
+       "crypto/sha256"
+       "fmt"
+       "io"
+       "os"
+       "path/filepath"
+       "strings"
+       "syscall"
+
+       "golang.org/x/tools/cmd/splitdwarf/internal/macho"
+)
+
+const (
+       pageAlign = 12 // 4096 = 1 << 12
+)
+
+func note(format string, why ...interface{}) {
+       fmt.Fprintf(os.Stderr, format+"\n", why...)
+}
+
+func fail(format string, why ...interface{}) {
+       note(format, why...)
+       os.Exit(1)
+}
+
+// splitdwarf inputexe [ outputdwarf ]
+func main() {
+       if len(os.Args) < 2 || len(os.Args) > 3 {
+               fmt.Printf(`
+Usage: %s input_exe [ output_dsym ]
+Reads the executable input_exe, uncompresses and copies debugging
+information into output_dsym. If output_dsym is not specified,
+the path
+      input_exe.dSYM/Contents/Resources/DWARF/input_exe
+is used instead.  That is the path that gdb and lldb expect
+on OSX.  Input_exe needs a UUID segment; if that is missing,
+then one is created and added.  In that case, the permissions
+for input_exe need to allow writing.
+`, os.Args[0])
+               return
+       }
+
+       // Read input, find DWARF, be sure it looks right
+       inputExe := os.Args[1]
+       exeFile, err := os.Open(inputExe)
+       if err != nil {
+               fail("%v", err)
+       }
+       exeMacho, err := macho.NewFile(exeFile)
+       if err != nil {
+               fail("(internal) Couldn't create macho, %v", err)
+       }
+       // Postpone dealing with output till input is known-good
+
+       // describe(&exeMacho.FileTOC)
+
+       // Offsets into __LINKEDIT:
+       //
+       // Command LC_SYMTAB =
+       //  (1) number of symbols at file offset (within link edit section) of 16-byte symbol table entries
+       // struct {
+       //  StringTableIndex uint32
+       //  Type, SectionIndex uint8
+       //  Description uint16
+       //  Value uint64
+       // }
+       //
+       // (2) string table offset and size.  Strings are zero-byte terminated.  First must be " ".
+       //
+       // Command LC_DYSYMTAB = indices within symtab (above), except for IndSym
+       //   IndSym Offset = file offset (within link edit section) of 4-byte indices within symtab.
+       //
+       // Section __TEXT.__symbol_stub1.
+       //   Offset and size (Reserved2) locate and describe a table for thios section.
+       //   Symbols beginning at IndirectSymIndex (Reserved1) (see LC_DYSYMTAB.IndSymOffset) refer to this table.
+       //   (These table entries are apparently PLTs [Procedure Linkage Table/Trampoline])
+       //
+       // Section __DATA.__nl_symbol_ptr.
+       //   Reserved1 seems to be an index within the Indirect symbols (see LC_DYSYMTAB.IndSymOffset)
+       //   Some of these symbols appear to be duplicates of other indirect symbols appearing early
+       //
+       // Section __DATA.__la_symbol_ptr.
+       //   Reserved1 seems to be an index within the Indirect symbols (see LC_DYSYMTAB.IndSymOffset)
+       //   Some of these symbols appear to be duplicates of other indirect symbols appearing early
+       //
+
+       // Create a File for the output dwarf.
+       // Copy header, file type is MH_DSYM
+       // Copy the relevant load commands
+
+       // LoadCmdUuid
+       // Symtab -- very abbreviated (Use DYSYMTAB Iextdefsym, Nextdefsym to identify these).
+       // Segment __PAGEZERO
+       // Segment __TEXT (zero the size, zero the offset of each section)
+       // Segment __DATA (zero the size, zero the offset of each section)
+       // Segment __LINKEDIT (contains the symbols and strings from Symtab)
+       // Segment __DWARF (uncompressed)
+
+       var uuid *macho.Uuid
+       for _, l := range exeMacho.Loads {
+               switch l.Command() {
+               case macho.LcUuid:
+                       uuid = l.(*macho.Uuid)
+               }
+       }
+
+       // Ensure a given load is not nil
+       nonnilC := func(l macho.Load, s string) {
+               if l == nil {
+                       fail("input file %s lacks load command %s", inputExe, s)
+               }
+       }
+
+       // Find a segment by name and ensure it is not nil
+       nonnilS := func(s string) *macho.Segment {
+               l := exeMacho.Segment(s)
+               if l == nil {
+                       fail("input file %s lacks segment %s", inputExe, s)
+               }
+               return l
+       }
+
+       newtoc := exeMacho.FileTOC.DerivedCopy(macho.MhDsym, 0)
+
+       symtab := exeMacho.Symtab
+       dysymtab := exeMacho.Dysymtab // Not appearing in output, but necessary to construct output
+       nonnilC(symtab, "symtab")
+       nonnilC(dysymtab, "dysymtab")
+       text := nonnilS("__TEXT")
+       data := nonnilS("__DATA")
+       linkedit := nonnilS("__LINKEDIT")
+       pagezero := nonnilS("__PAGEZERO")
+
+       newtext := text.CopyZeroed()
+       newdata := data.CopyZeroed()
+       newsymtab := symtab.Copy()
+
+       // Linkedit segment contain symbols and strings;
+       // Symtab refers to offsets into linkedit.
+       // This next bit initializes newsymtab and sets up data structures for the linkedit segment
+       linkeditsyms := []macho.Nlist64{}
+       linkeditstrings := []string{}
+
+       // Linkedit will begin at the second page, i.e., offset is one page from beginning
+       // Symbols come first
+       linkeditsymbase := uint32(1) << pageAlign
+
+       // Strings come second, offset by the number of symbols times their size.
+       // Only those symbols from dysymtab.defsym are written into the debugging information.
+       linkeditstringbase := linkeditsymbase + exeMacho.FileTOC.SymbolSize()*dysymtab.Nextdefsym
+
+       // The first two bytes of the strings are reserved for space, null (' ', \000)
+       linkeditstringcur := uint32(2)
+
+       newsymtab.Syms = newsymtab.Syms[:0]
+       newsymtab.Symoff = linkeditsymbase
+       newsymtab.Stroff = linkeditstringbase
+       newsymtab.Nsyms = dysymtab.Nextdefsym
+       for i := uint32(0); i < dysymtab.Nextdefsym; i++ {
+               ii := i + dysymtab.Iextdefsym
+               oldsym := symtab.Syms[ii]
+               newsymtab.Syms = append(newsymtab.Syms, oldsym)
+
+               linkeditsyms = append(linkeditsyms, macho.Nlist64{Name: uint32(linkeditstringcur),
+                       Type: oldsym.Type, Sect: oldsym.Sect, Desc: oldsym.Desc, Value: oldsym.Value})
+               linkeditstringcur += uint32(len(oldsym.Name)) + 1
+               linkeditstrings = append(linkeditstrings, oldsym.Name)
+       }
+       newsymtab.Strsize = linkeditstringcur
+
+       exeNeedsUuid := uuid == nil
+       if exeNeedsUuid {
+               uuid = &macho.Uuid{macho.UuidCmd{LoadCmd: macho.LcUuid}}
+               uuid.Len = uuid.LoadSize(newtoc)
+               copy(uuid.Id[0:], contentuuid(&exeMacho.FileTOC)[0:16])
+               uuid.Id[6] = uuid.Id[6]&^0xf0 | 0x40 // version 4 (pseudo-random); see section 4.1.3
+               uuid.Id[8] = uuid.Id[8]&^0xc0 | 0x80 // variant bits; see section 4.1.1
+       }
+       newtoc.AddLoad(uuid)
+
+       // For the specified segment (assumed to be in exeMacho) make a copy of its
+       // sections with appropriate fields zeroed out, and append them to the
+       // currently-last segment in newtoc.
+       copyZOdSections := func(g *macho.Segment) {
+               for i := g.Firstsect; i < g.Firstsect+g.Nsect; i++ {
+                       s := exeMacho.Sections[i].Copy()
+                       s.Offset = 0
+                       s.Reloff = 0
+                       s.Nreloc = 0
+                       newtoc.AddSection(s)
+               }
+       }
+
+       newtoc.AddLoad(newsymtab)
+       newtoc.AddSegment(pagezero)
+       newtoc.AddSegment(newtext)
+       copyZOdSections(text)
+       newtoc.AddSegment(newdata)
+       copyZOdSections(data)
+
+       newlinkedit := linkedit.Copy()
+       newlinkedit.Offset = uint64(linkeditsymbase)
+       newlinkedit.Filesz = uint64(linkeditstringcur)
+       newlinkedit.Addr = macho.RoundUp(newdata.Addr+newdata.Memsz, 1<<pageAlign) // Follows data sections in file
+       newlinkedit.Memsz = macho.RoundUp(newlinkedit.Filesz, 1<<pageAlign)
+       // The rest should copy over fine.
+       newtoc.AddSegment(newlinkedit)
+
+       dwarf := nonnilS("__DWARF")
+       newdwarf := dwarf.CopyZeroed()
+       newdwarf.Offset = macho.RoundUp(newlinkedit.Offset+newlinkedit.Filesz, 1<<pageAlign)
+       newdwarf.Filesz = dwarf.UncompressedSize(&exeMacho.FileTOC, 1)
+       newdwarf.Addr = newlinkedit.Addr + newlinkedit.Memsz // Follows linkedit sections in file.
+       newdwarf.Memsz = macho.RoundUp(newdwarf.Filesz, 1<<pageAlign)
+       newtoc.AddSegment(newdwarf)
+
+       // Map out Dwarf sections (that is, this is section descriptors, not their contents).
+       offset := uint32(newdwarf.Offset)
+       for i := dwarf.Firstsect; i < dwarf.Firstsect+dwarf.Nsect; i++ {
+               o := exeMacho.Sections[i]
+               s := o.Copy()
+               s.Offset = offset
+               us := o.UncompressedSize()
+               if s.Size < us {
+                       s.Size = uint64(us)
+                       s.Align = 0 // This is apparently true for debugging sections; not sure if it generalizes.
+               }
+               offset += uint32(us)
+               if strings.HasPrefix(s.Name, "__z") {
+                       s.Name = "__" + s.Name[3:] // remove "z"
+               }
+               s.Reloff = 0
+               s.Nreloc = 0
+               newtoc.AddSection(s)
+       }
+
+       // Write segments/sections.
+       // Only dwarf and linkedit contain anything interesting.
+
+       // Memory map the output file to get the buffer directly.
+       outDwarf := inputExe + ".dSYM/Contents/Resources/DWARF"
+       if len(os.Args) > 2 {
+               outDwarf = os.Args[2]
+       } else {
+               err := os.MkdirAll(outDwarf, 0755)
+               if err != nil {
+                       fail("%v", err)
+               }
+               outDwarf = filepath.Join(outDwarf, filepath.Base(inputExe))
+       }
+       dwarfFile, buffer := CreateMmapFile(outDwarf, int64(newtoc.FileSize()))
+
+       // (1) Linkedit segment
+       // Symbol table
+       offset = uint32(newlinkedit.Offset)
+       for i := range linkeditsyms {
+               if exeMacho.Magic == macho.Magic64 {
+                       offset += linkeditsyms[i].Put64(buffer[offset:], newtoc.ByteOrder)
+               } else {
+                       offset += linkeditsyms[i].Put32(buffer[offset:], newtoc.ByteOrder)
+               }
+       }
+
+       // Initial two bytes of string table, followed by actual zero-terminated strings.
+       buffer[linkeditstringbase] = ' '
+       buffer[linkeditstringbase+1] = 0
+       offset = linkeditstringbase + 2
+       for _, str := range linkeditstrings {
+               for i := 0; i < len(str); i++ {
+                       buffer[offset] = str[i]
+                       offset++
+               }
+               buffer[offset] = 0
+               offset++
+       }
+
+       // (2) DWARF segment
+       ioff := newdwarf.Firstsect - dwarf.Firstsect
+       for i := dwarf.Firstsect; i < dwarf.Firstsect+dwarf.Nsect; i++ {
+               s := exeMacho.Sections[i]
+               j := i + ioff
+               s.PutUncompressedData(buffer[newtoc.Sections[j].Offset:])
+       }
+
+       // Because "text" overlaps the header and the loads, write them afterwards, just in case.
+       // Write header.
+       newtoc.Put(buffer)
+
+       err = syscall.Munmap(buffer)
+       if err != nil {
+               fail("Munmap %s for dwarf output failed, %v", outDwarf, err)
+       }
+       err = dwarfFile.Close()
+       if err != nil {
+               fail("Close %s for dwarf output after mmap/munmap failed, %v", outDwarf, err)
+       }
+
+       if exeNeedsUuid { // Map the original exe, modify the header, and write the UUID command
+               hdr := exeMacho.FileTOC.FileHeader
+               oldCommandEnd := hdr.SizeCommands + newtoc.HdrSize()
+               hdr.NCommands += 1
+               hdr.SizeCommands += uuid.LoadSize(newtoc)
+
+               mapf, err := os.OpenFile(inputExe, os.O_RDWR, 0)
+               if err != nil {
+                       fail("Updating UUID in binary failed, %v", err)
+               }
+               exebuf, err := syscall.Mmap(int(mapf.Fd()), 0, int(macho.RoundUp(uint64(hdr.SizeCommands), 1<<pageAlign)),
+                       syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_FILE|syscall.MAP_SHARED)
+               if err != nil {
+                       fail("Mmap of %s for UUID update failed, %v", inputExe, err)
+               }
+               _ = hdr.Put(exebuf, newtoc.ByteOrder)
+               _ = uuid.Put(exebuf[oldCommandEnd:], newtoc.ByteOrder)
+               err = syscall.Munmap(exebuf)
+               if err != nil {
+                       fail("Munmap of %s for UUID update failed, %v", inputExe, err)
+               }
+       }
+}
+
+// CreateMmapFile creates the file 'outDwarf' of the specified size, mmaps that file,
+// and returns the file descriptor and mapped buffer.
+func CreateMmapFile(outDwarf string, size int64) (*os.File, []byte) {
+       dwarfFile, err := os.OpenFile(outDwarf, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
+       if err != nil {
+               fail("Open for mmap failed, %v", err)
+       }
+       err = os.Truncate(outDwarf, size)
+       if err != nil {
+               fail("Truncate/extend of %s to %d bytes failed, %v", dwarfFile, size, err)
+       }
+       buffer, err := syscall.Mmap(int(dwarfFile.Fd()), 0, int(size), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_FILE|syscall.MAP_SHARED)
+       if err != nil {
+               fail("Mmap %s for dwarf output update failed, %v", outDwarf, err)
+       }
+       return dwarfFile, buffer
+}
+
+func describe(exem *macho.FileTOC) {
+       note("Type = %s, Flags=0x%x", exem.Type, uint32(exem.Flags))
+       for i, l := range exem.Loads {
+               if s, ok := l.(*macho.Segment); ok {
+                       fmt.Printf("Load %d is Segment %s, offset=0x%x, filesz=%d, addr=0x%x, memsz=%d, nsect=%d\n", i, s.Name,
+                               s.Offset, s.Filesz, s.Addr, s.Memsz, s.Nsect)
+                       for j := uint32(0); j < s.Nsect; j++ {
+                               c := exem.Sections[j+s.Firstsect]
+                               fmt.Printf("   Section %s, offset=0x%x, size=%d, addr=0x%x, flags=0x%x, nreloc=%d, res1=%d, res2=%d, res3=%d\n", c.Name, c.Offset, c.Size, c.Addr, c.Flags, c.Nreloc, c.Reserved1, c.Reserved2, c.Reserved3)
+                       }
+               } else {
+                       fmt.Printf("Load %d is %v\n", i, l)
+               }
+       }
+       if exem.SizeCommands != exem.LoadSize() {
+               fail("recorded command size %d does not equal computed command size %d", exem.SizeCommands, exem.LoadSize())
+       } else {
+               note("recorded command size %d, computed command size %d", exem.SizeCommands, exem.LoadSize())
+       }
+       note("File size is %d", exem.FileSize())
+}
+
+// contentuuid returns a UUID derived from (some of) the content of an executable.
+// specifically included are the non-DWARF sections, specifically excluded are things
+// that surely depend on the presence or absence of DWARF sections (e.g., section
+// numbers, positions with file, number of load commands).
+// (It was considered desirable if this was insensitive to the presence of the
+// __DWARF segment, however because it is not last, it moves other segments,
+// whose contents appear to contain file offset references.)
+func contentuuid(exem *macho.FileTOC) []byte {
+       h := sha256.New()
+       for _, l := range exem.Loads {
+               if l.Command() == macho.LcUuid {
+                       continue
+               }
+               if s, ok := l.(*macho.Segment); ok {
+                       if s.Name == "__DWARF" || s.Name == "__PAGEZERO" {
+                               continue
+                       }
+                       for j := uint32(0); j < s.Nsect; j++ {
+                               c := exem.Sections[j+s.Firstsect]
+                               io.Copy(h, c.Open())
+                       }
+               } // Getting dependence on other load commands right is fiddly.
+       }
+       return h.Sum(nil)
+}