// Copyright 2010 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. // TODO/NICETOHAVE: // - eliminate DW_CLS_ if not used // - package info in compilation units // - assign types to their packages // - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg // ptype struct '[]uint8' and qualifiers need to be quoted away // - file:line info for variables // - make strings a typedef so prettyprinters can see the underlying string type package ld import ( "cmd/internal/objabi" "cmd/link/internal/loader" "cmd/link/internal/sym" "log" ) func isDwarf64(ctxt *Link) bool { return ctxt.HeadType == objabi.Haix } // dwarfSecInfo2 is a replica of the dwarfSecInfo struct but with // *sym.Symbol content instead of loader.Sym content. type dwarfSecInfo2 struct { syms []*sym.Symbol } func (dsi *dwarfSecInfo2) secSym() *sym.Symbol { if len(dsi.syms) == 0 { return nil } return dsi.syms[0] } func (dsi *dwarfSecInfo2) subSyms() []*sym.Symbol { if len(dsi.syms) == 0 { return []*sym.Symbol{} } return dsi.syms[1:] } var dwarfp []dwarfSecInfo2 /* * Elf. */ func dwarfaddshstrings(ctxt *Link, shstrtab *loader.SymbolBuilder) { if *FlagW { // disable dwarf return } secs := []string{"abbrev", "frame", "info", "loc", "line", "pubnames", "pubtypes", "gdb_scripts", "ranges"} for _, sec := range secs { shstrtab.Addstring(".debug_" + sec) if ctxt.IsExternal() { shstrtab.Addstring(elfRelType + ".debug_" + sec) } else { shstrtab.Addstring(".zdebug_" + sec) } } } // Add section symbols for DWARF debug info. This is called before // dwarfaddelfheaders. func dwarfaddelfsectionsyms(ctxt *Link) { if *FlagW { // disable dwarf return } if ctxt.LinkMode != LinkExternal { return } s := ctxt.Syms.Lookup(".debug_info", 0) putelfsectionsym(ctxt, ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum) s = ctxt.Syms.Lookup(".debug_abbrev", 0) putelfsectionsym(ctxt, ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum) s = ctxt.Syms.Lookup(".debug_line", 0) putelfsectionsym(ctxt, ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum) s = ctxt.Syms.Lookup(".debug_frame", 0) putelfsectionsym(ctxt, ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum) s = ctxt.Syms.Lookup(".debug_loc", 0) if s.Sect != nil { putelfsectionsym(ctxt, ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum) } s = ctxt.Syms.Lookup(".debug_ranges", 0) if s.Sect != nil { putelfsectionsym(ctxt, ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum) } } // dwarfcompress compresses the DWARF sections. Relocations are applied // on the fly. After this, dwarfp will contain a different (new) set of // symbols, and sections may have been replaced. func dwarfcompress(ctxt *Link) { // compressedSect is a helper type for parallelizing compression. type compressedSect struct { index int compressed []byte syms []loader.Sym } supported := ctxt.IsELF || ctxt.IsWindows() || ctxt.IsDarwin() if !ctxt.compressDWARF || !supported || ctxt.IsExternal() { return } var compressedCount int resChannel := make(chan compressedSect) for i := range dwarfp2 { go func(resIndex int, syms []loader.Sym) { resChannel <- compressedSect{resIndex, compressSyms(ctxt, syms), syms} }(compressedCount, dwarfp2[i].syms) compressedCount++ } res := make([]compressedSect, compressedCount) for ; compressedCount > 0; compressedCount-- { r := <-resChannel res[r.index] = r } ldr := ctxt.loader var newDwarfp []dwarfSecInfo Segdwarf.Sections = Segdwarf.Sections[:0] for _, z := range res { s := z.syms[0] if z.compressed == nil { // Compression didn't help. ds := dwarfSecInfo{syms: z.syms} newDwarfp = append(newDwarfp, ds) Segdwarf.Sections = append(Segdwarf.Sections, ldr.SymSect(s)) } else { compressedSegName := ".zdebug_" + ldr.SymSect(s).Name[len(".debug_"):] sect := addsection(ctxt.loader, ctxt.Arch, &Segdwarf, compressedSegName, 04) sect.Align = 1 sect.Length = uint64(len(z.compressed)) newSym := ldr.CreateSymForUpdate(compressedSegName, 0) newSym.SetReachable(true) newSym.SetData(z.compressed) newSym.SetSize(int64(len(z.compressed))) ldr.SetSymSect(newSym.Sym(), sect) ds := dwarfSecInfo{syms: []loader.Sym{newSym.Sym()}} newDwarfp = append(newDwarfp, ds) // compressed symbols are no longer needed. for _, s := range z.syms { ldr.SetAttrReachable(s, false) ldr.FreeSym(s) } } } dwarfp2 = newDwarfp // Re-compute the locations of the compressed DWARF symbols // and sections, since the layout of these within the file is // based on Section.Vaddr and Symbol.Value. pos := Segdwarf.Vaddr var prevSect *sym.Section for _, si := range dwarfp2 { for _, s := range si.syms { ldr.SetSymValue(s, int64(pos)) sect := ldr.SymSect(s) if sect != prevSect { sect.Vaddr = uint64(pos) prevSect = sect } if ldr.SubSym(s) != 0 { log.Fatalf("%s: unexpected sub-symbols", ldr.SymName(s)) } pos += uint64(ldr.SymSize(s)) if ctxt.IsWindows() { pos = uint64(Rnd(int64(pos), PEFILEALIGN)) } } } Segdwarf.Length = pos - Segdwarf.Vaddr } type compilationUnitByStartPC []*sym.CompilationUnit func (v compilationUnitByStartPC) Len() int { return len(v) } func (v compilationUnitByStartPC) Swap(i, j int) { v[i], v[j] = v[j], v[i] } func (v compilationUnitByStartPC) Less(i, j int) bool { switch { case len(v[i].Textp2) == 0 && len(v[j].Textp2) == 0: return v[i].Lib.Pkg < v[j].Lib.Pkg case len(v[i].Textp2) != 0 && len(v[j].Textp2) == 0: return true case len(v[i].Textp2) == 0 && len(v[j].Textp2) != 0: return false default: return v[i].PCs[0].Start < v[j].PCs[0].Start } }