2019-11-20 10:43:11 -05:00
|
|
|
// Copyright 2019 The Go Authors. All rights reserved.
|
2015-02-27 22:57:28 -05:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2015-03-05 13:57:36 -05:00
|
|
|
// TODO/NICETOHAVE:
|
|
|
|
|
// - eliminate DW_CLS_ if not used
|
|
|
|
|
// - package info in compilation units
|
2018-09-25 11:52:24 +02:00
|
|
|
// - assign types to their packages
|
2015-03-05 13:57:36 -05:00
|
|
|
// - 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
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
package ld
|
|
|
|
|
|
|
|
|
|
import (
|
2016-07-28 13:04:41 -04:00
|
|
|
"cmd/internal/dwarf"
|
2020-02-14 16:12:51 -05:00
|
|
|
"cmd/internal/obj"
|
2017-04-18 12:53:25 -07:00
|
|
|
"cmd/internal/objabi"
|
2020-02-14 16:12:51 -05:00
|
|
|
"cmd/internal/src"
|
2017-10-01 02:37:20 +00:00
|
|
|
"cmd/internal/sys"
|
2019-11-20 10:43:11 -05:00
|
|
|
"cmd/link/internal/loader"
|
2017-10-04 17:54:04 -04:00
|
|
|
"cmd/link/internal/sym"
|
2024-09-03 17:46:10 +00:00
|
|
|
"cmp"
|
2015-02-27 22:57:28 -05:00
|
|
|
"fmt"
|
2023-01-13 16:12:47 -05:00
|
|
|
"internal/abi"
|
2021-04-15 23:05:49 -04:00
|
|
|
"internal/buildcfg"
|
2016-03-14 09:23:04 -07:00
|
|
|
"log"
|
cmd/link: emit include directories in DWARF line table prologue
This patch changes the way the linker emits the DWARF line table
prologue, specifically the file table. Previously files were left
unmodified, and the directory table was empty. For each compilation
unit we now scan the unit file table and build up a common set of
directories, emit them into the directory table, and then emit file
entries that refer to the dirs. This provides a modest binary size
savings.
For kubernetes kubelet:
$ objdump -h /tmp/kubelet.old | fgrep debug_line
36 .zdebug_line 019a55f5 0000000000000000 0000000000000000 084a5123 2**0
$ objdump -h /tmp/kubelet.new | fgrep debug_line
36 .zdebug_line 01146fd2 0000000000000000 0000000000000000 084a510a 2**0
[where the value following the section name above is the section size
in hex, so roughly a 30% decrease in this case.]
The actual savings will depend on the length of the pathnames
involved, so it's hard to really pin down how much savings we'll see
here. In addition, emitting the files this way reduces the
"compressibility" of the line table, so there could even be cases
where we don't win at all.
Updates #6853, #19784, #36495.
Change-Id: I298d8561da5ed3ebc9d38aa772874851baa2f4f4
Reviewed-on: https://go-review.googlesource.com/c/go/+/263017
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Trust: Than McIntosh <thanm@google.com>
2020-10-16 09:22:31 -04:00
|
|
|
"path"
|
2020-06-12 09:04:28 -04:00
|
|
|
"runtime"
|
2024-09-03 17:46:10 +00:00
|
|
|
"slices"
|
2015-02-27 22:57:28 -05:00
|
|
|
"strings"
|
2020-06-12 09:04:28 -04:00
|
|
|
"sync"
|
2015-02-27 22:57:28 -05:00
|
|
|
)
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
// dwctxt is a wrapper intended to satisfy the method set of
|
2019-11-20 10:43:11 -05:00
|
|
|
// dwarf.Context, so that functions like dwarf.PutAttrs will work with
|
|
|
|
|
// DIEs that use loader.Sym as opposed to *sym.Symbol. It is also
|
|
|
|
|
// being used as a place to store tables/maps that are useful as part
|
|
|
|
|
// of type conversion (this is just a convenience; it would be easy to
|
|
|
|
|
// split these things out into another type if need be).
|
2020-05-15 18:35:05 -04:00
|
|
|
type dwctxt struct {
|
2016-08-19 22:40:38 -04:00
|
|
|
linkctxt *Link
|
2019-11-20 10:43:11 -05:00
|
|
|
ldr *loader.Loader
|
|
|
|
|
arch *sys.Arch
|
|
|
|
|
|
|
|
|
|
// This maps type name string (e.g. "uintptr") to loader symbol for
|
2021-05-08 00:45:06 +07:00
|
|
|
// the DWARF DIE for that type (e.g. "go:info.type.uintptr")
|
2019-11-20 10:43:11 -05:00
|
|
|
tmap map[string]loader.Sym
|
|
|
|
|
|
|
|
|
|
// This maps loader symbol for the DWARF DIE symbol generated for
|
2021-05-08 00:45:06 +07:00
|
|
|
// a type (e.g. "go:info.uintptr") to the type symbol itself
|
|
|
|
|
// ("type:uintptr").
|
2019-11-20 10:43:11 -05:00
|
|
|
// FIXME: try converting this map (and the next one) to a single
|
|
|
|
|
// array indexed by loader.Sym -- this may perform better.
|
|
|
|
|
rtmap map[loader.Sym]loader.Sym
|
|
|
|
|
|
2021-05-08 00:45:06 +07:00
|
|
|
// This maps Go type symbol (e.g. "type:XXX") to loader symbol for
|
|
|
|
|
// the typedef DIE for that type (e.g. "go:info.XXX..def")
|
2019-11-20 10:43:11 -05:00
|
|
|
tdmap map[loader.Sym]loader.Sym
|
|
|
|
|
|
|
|
|
|
// Cache these type symbols, so as to avoid repeatedly looking them up
|
|
|
|
|
typeRuntimeEface loader.Sym
|
|
|
|
|
typeRuntimeIface loader.Sym
|
|
|
|
|
uintptrInfoSym loader.Sym
|
2020-06-12 09:04:28 -04:00
|
|
|
|
|
|
|
|
// Used at various points in that parallel portion of DWARF gen to
|
|
|
|
|
// protect against conflicting updates to globals (such as "gdbscript")
|
|
|
|
|
dwmu *sync.Mutex
|
2019-11-20 10:43:11 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-19 16:16:17 -05:00
|
|
|
// dwSym wraps a loader.Sym; this type is meant to obey the interface
|
|
|
|
|
// rules for dwarf.Sym from the cmd/internal/dwarf package. DwDie and
|
|
|
|
|
// DwAttr objects contain references to symbols via this type.
|
|
|
|
|
type dwSym loader.Sym
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) PtrSize() int {
|
2019-11-20 10:43:11 -05:00
|
|
|
return c.arch.PtrSize
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
|
2023-08-31 21:17:46 -07:00
|
|
|
func (c dwctxt) Size(s dwarf.Sym) int64 {
|
|
|
|
|
return int64(len(c.ldr.Data(loader.Sym(s.(dwSym)))))
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) AddInt(s dwarf.Sym, size int, i int64) {
|
2020-02-19 16:16:17 -05:00
|
|
|
ds := loader.Sym(s.(dwSym))
|
|
|
|
|
dsu := c.ldr.MakeSymbolUpdater(ds)
|
2019-11-20 10:43:11 -05:00
|
|
|
dsu.AddUintXX(c.arch, uint64(i), size)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) AddBytes(s dwarf.Sym, b []byte) {
|
2020-02-19 16:16:17 -05:00
|
|
|
ds := loader.Sym(s.(dwSym))
|
|
|
|
|
dsu := c.ldr.MakeSymbolUpdater(ds)
|
2019-11-20 10:43:11 -05:00
|
|
|
dsu.AddBytes(b)
|
2016-07-28 13:04:41 -04:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) AddString(s dwarf.Sym, v string) {
|
2020-02-19 16:16:17 -05:00
|
|
|
ds := loader.Sym(s.(dwSym))
|
|
|
|
|
dsu := c.ldr.MakeSymbolUpdater(ds)
|
2019-11-20 10:43:11 -05:00
|
|
|
dsu.Addstring(v)
|
2016-07-28 13:04:41 -04:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
|
2020-02-19 16:16:17 -05:00
|
|
|
ds := loader.Sym(s.(dwSym))
|
|
|
|
|
dsu := c.ldr.MakeSymbolUpdater(ds)
|
2016-07-28 13:04:41 -04:00
|
|
|
if value != 0 {
|
2019-11-20 10:43:11 -05:00
|
|
|
value -= dsu.Value()
|
2016-07-28 13:04:41 -04:00
|
|
|
}
|
2020-02-19 16:16:17 -05:00
|
|
|
tgtds := loader.Sym(data.(dwSym))
|
|
|
|
|
dsu.AddAddrPlus(c.arch, tgtds, value)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) AddCURelativeAddress(s dwarf.Sym, data interface{}, value int64) {
|
2020-02-19 16:16:17 -05:00
|
|
|
ds := loader.Sym(s.(dwSym))
|
|
|
|
|
dsu := c.ldr.MakeSymbolUpdater(ds)
|
2019-04-02 17:26:49 -04:00
|
|
|
if value != 0 {
|
2019-11-20 10:43:11 -05:00
|
|
|
value -= dsu.Value()
|
2019-04-02 17:26:49 -04:00
|
|
|
}
|
2020-02-19 16:16:17 -05:00
|
|
|
tgtds := loader.Sym(data.(dwSym))
|
|
|
|
|
dsu.AddCURelativeAddrPlus(c.arch, tgtds, value)
|
2019-04-02 17:26:49 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
|
2020-02-19 16:16:17 -05:00
|
|
|
ds := loader.Sym(s.(dwSym))
|
|
|
|
|
dsu := c.ldr.MakeSymbolUpdater(ds)
|
|
|
|
|
tds := loader.Sym(t.(dwSym))
|
2016-07-28 13:04:41 -04:00
|
|
|
switch size {
|
|
|
|
|
default:
|
2020-02-19 16:16:17 -05:00
|
|
|
c.linkctxt.Errorf(ds, "invalid size %d in adddwarfref\n", size)
|
2020-03-28 16:46:47 -04:00
|
|
|
case c.arch.PtrSize, 4:
|
2016-07-28 13:04:41 -04:00
|
|
|
}
|
2020-03-28 16:46:47 -04:00
|
|
|
dsu.AddSymRef(c.arch, tds, ofs, objabi.R_ADDROFF, size)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
|
2018-09-28 16:44:30 +02:00
|
|
|
size := 4
|
|
|
|
|
if isDwarf64(c.linkctxt) {
|
|
|
|
|
size = 8
|
|
|
|
|
}
|
2020-02-19 16:16:17 -05:00
|
|
|
ds := loader.Sym(s.(dwSym))
|
|
|
|
|
dsu := c.ldr.MakeSymbolUpdater(ds)
|
2020-03-28 16:46:47 -04:00
|
|
|
tds := loader.Sym(t.(dwSym))
|
|
|
|
|
switch size {
|
|
|
|
|
default:
|
|
|
|
|
c.linkctxt.Errorf(ds, "invalid size %d in adddwarfref\n", size)
|
|
|
|
|
case c.arch.PtrSize, 4:
|
|
|
|
|
}
|
|
|
|
|
dsu.AddSymRef(c.arch, tds, ofs, objabi.R_DWARFSECREF, size)
|
2018-04-12 17:07:14 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) Logf(format string, args ...interface{}) {
|
2017-10-06 11:32:28 -04:00
|
|
|
c.linkctxt.Logf(format, args...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// At the moment these interfaces are only used in the compiler.
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) CurrentOffset(s dwarf.Sym) int64 {
|
2017-10-06 11:32:28 -04:00
|
|
|
panic("should be used only in the compiler")
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) RecordDclReference(s dwarf.Sym, t dwarf.Sym, dclIdx int, inlIndex int) {
|
2017-10-06 11:32:28 -04:00
|
|
|
panic("should be used only in the compiler")
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (c dwctxt) RecordChildDieOffsets(s dwarf.Sym, vars []*dwarf.Var, offsets []int32) {
|
2017-10-06 11:32:28 -04:00
|
|
|
panic("should be used only in the compiler")
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-10 09:57:10 -04:00
|
|
|
func isDwarf64(ctxt *Link) bool {
|
|
|
|
|
return ctxt.HeadType == objabi.Haix
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-23 08:40:32 +00:00
|
|
|
// https://sourceware.org/gdb/onlinedocs/gdb/dotdebug_005fgdb_005fscripts-section.html
|
|
|
|
|
// Each entry inside .debug_gdb_scripts section begins with a non-null prefix
|
|
|
|
|
// byte that specifies the kind of entry. The following entries are supported:
|
|
|
|
|
const (
|
|
|
|
|
GdbScriptPythonFileId = 1
|
|
|
|
|
GdbScriptSchemeFileId = 3
|
|
|
|
|
GdbScriptPythonTextId = 4
|
|
|
|
|
GdbScriptSchemeTextId = 6
|
|
|
|
|
)
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
var gdbscript string
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2020-04-17 09:11:57 -04:00
|
|
|
// dwarfSecInfo holds information about a DWARF output section,
|
|
|
|
|
// specifically a section symbol and a list of symbols contained in
|
|
|
|
|
// that section. On the syms list, the first symbol will always be the
|
|
|
|
|
// section symbol, then any remaining symbols (if any) will be
|
|
|
|
|
// sub-symbols in that section. Note that for some sections (eg:
|
|
|
|
|
// .debug_abbrev), the section symbol is all there is (all content is
|
|
|
|
|
// contained in it). For other sections (eg: .debug_info), the section
|
|
|
|
|
// symbol is empty and all the content is in the sub-symbols. Finally
|
|
|
|
|
// there are some sections (eg: .debug_ranges) where it is a mix (both
|
|
|
|
|
// the section symbol and the sub-symbols have content)
|
|
|
|
|
type dwarfSecInfo struct {
|
|
|
|
|
syms []loader.Sym
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// secSym returns the section symbol for the section.
|
|
|
|
|
func (dsi *dwarfSecInfo) secSym() loader.Sym {
|
|
|
|
|
if len(dsi.syms) == 0 {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
return dsi.syms[0]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// subSyms returns a list of sub-symbols for the section.
|
|
|
|
|
func (dsi *dwarfSecInfo) subSyms() []loader.Sym {
|
|
|
|
|
if len(dsi.syms) == 0 {
|
|
|
|
|
return []loader.Sym{}
|
|
|
|
|
}
|
|
|
|
|
return dsi.syms[1:]
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
// dwarfp stores the collected DWARF symbols created during
|
2020-04-17 09:11:57 -04:00
|
|
|
// dwarf generation.
|
2020-05-15 18:35:05 -04:00
|
|
|
var dwarfp []dwarfSecInfo
|
2016-03-14 09:23:04 -07:00
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) writeabbrev() dwarfSecInfo {
|
2020-06-12 09:35:42 -04:00
|
|
|
abrvs := d.ldr.CreateSymForUpdate(".debug_abbrev", 0)
|
|
|
|
|
abrvs.SetType(sym.SDWARFSECT)
|
|
|
|
|
abrvs.AddBytes(dwarf.GetAbbrev())
|
|
|
|
|
return dwarfSecInfo{syms: []loader.Sym{abrvs.Sym()}}
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
var dwtypes dwarf.DWDie
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// newattr attaches a new attribute to the specified DIE.
|
|
|
|
|
//
|
|
|
|
|
// FIXME: at the moment attributes are stored in a linked list in a
|
|
|
|
|
// fairly space-inefficient way -- it might be better to instead look
|
|
|
|
|
// up all attrs in a single large table, then store indices into the
|
|
|
|
|
// table in the DIE. This would allow us to common up storage for
|
|
|
|
|
// attributes that are shared by many DIEs (ex: byte size of N).
|
2021-07-01 09:27:46 -04:00
|
|
|
func newattr(die *dwarf.DWDie, attr uint16, cls int, value int64, data interface{}) {
|
2016-07-28 13:04:41 -04:00
|
|
|
a := new(dwarf.DWAttr)
|
|
|
|
|
a.Link = die.Attr
|
|
|
|
|
die.Attr = a
|
|
|
|
|
a.Atr = attr
|
|
|
|
|
a.Cls = uint8(cls)
|
|
|
|
|
a.Value = value
|
|
|
|
|
a.Data = data
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Each DIE (except the root ones) has at least 1 attribute: its
|
|
|
|
|
// name. getattr moves the desired one to the front so
|
|
|
|
|
// frequently searched ones are found faster.
|
2016-07-28 13:04:41 -04:00
|
|
|
func getattr(die *dwarf.DWDie, attr uint16) *dwarf.DWAttr {
|
|
|
|
|
if die.Attr.Atr == attr {
|
|
|
|
|
return die.Attr
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
a := die.Attr
|
|
|
|
|
b := a.Link
|
2015-02-27 22:57:28 -05:00
|
|
|
for b != nil {
|
2016-07-28 13:04:41 -04:00
|
|
|
if b.Atr == attr {
|
|
|
|
|
a.Link = b.Link
|
|
|
|
|
b.Link = die.Attr
|
|
|
|
|
die.Attr = b
|
2015-02-27 22:57:28 -05:00
|
|
|
return b
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a = b
|
2016-07-28 13:04:41 -04:00
|
|
|
b = b.Link
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-06 11:32:28 -04:00
|
|
|
// Every DIE manufactured by the linker has at least an AT_name
|
|
|
|
|
// attribute (but it will only be written out if it is listed in the abbrev).
|
|
|
|
|
// The compiler does create nameless DWARF DIEs (ex: concrete subprogram
|
|
|
|
|
// instance).
|
2019-11-20 10:43:11 -05:00
|
|
|
// FIXME: it would be more efficient to bulk-allocate DIEs.
|
2021-07-01 09:27:46 -04:00
|
|
|
func (d *dwctxt) newdie(parent *dwarf.DWDie, abbrev int, name string) *dwarf.DWDie {
|
2016-07-28 13:04:41 -04:00
|
|
|
die := new(dwarf.DWDie)
|
|
|
|
|
die.Abbrev = abbrev
|
|
|
|
|
die.Link = parent.Child
|
|
|
|
|
parent.Child = die
|
|
|
|
|
|
|
|
|
|
newattr(die, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len(name)), name)
|
|
|
|
|
|
2021-07-01 09:27:46 -04:00
|
|
|
// Sanity check: all DIEs created in the linker should be named.
|
|
|
|
|
if name == "" {
|
|
|
|
|
panic("nameless DWARF DIE")
|
2020-05-20 13:51:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var st sym.SymKind
|
|
|
|
|
switch abbrev {
|
2024-06-27 14:54:06 +00:00
|
|
|
case dwarf.DW_ABRV_FUNCTYPEPARAM, dwarf.DW_ABRV_FUNCTYPEOUTPARAM, dwarf.DW_ABRV_DOTDOTDOT, dwarf.DW_ABRV_STRUCTFIELD, dwarf.DW_ABRV_ARRAYRANGE:
|
2020-05-20 13:51:59 -04:00
|
|
|
// There are no relocations against these dies, and their names
|
|
|
|
|
// are not unique, so don't create a symbol.
|
|
|
|
|
return die
|
|
|
|
|
case dwarf.DW_ABRV_COMPUNIT, dwarf.DW_ABRV_COMPUNIT_TEXTLESS:
|
|
|
|
|
// Avoid collisions with "real" symbol names.
|
|
|
|
|
name = fmt.Sprintf(".pkg.%s.%d", name, len(d.linkctxt.compUnits))
|
|
|
|
|
st = sym.SDWARFCUINFO
|
|
|
|
|
case dwarf.DW_ABRV_VARIABLE:
|
|
|
|
|
st = sym.SDWARFVAR
|
|
|
|
|
default:
|
|
|
|
|
// Everything else is assigned a type of SDWARFTYPE. that
|
|
|
|
|
// this also includes loose ends such as STRUCT_FIELD.
|
|
|
|
|
st = sym.SDWARFTYPE
|
|
|
|
|
}
|
2021-07-01 09:27:46 -04:00
|
|
|
ds := d.ldr.LookupOrCreateSym(dwarf.InfoPrefix+name, 0)
|
2020-05-20 13:51:59 -04:00
|
|
|
dsu := d.ldr.MakeSymbolUpdater(ds)
|
|
|
|
|
dsu.SetType(st)
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(ds, true)
|
|
|
|
|
d.ldr.SetAttrReachable(ds, true)
|
|
|
|
|
die.Sym = dwSym(ds)
|
|
|
|
|
if abbrev >= dwarf.DW_ABRV_NULLTYPE && abbrev <= dwarf.DW_ABRV_TYPEDECL {
|
|
|
|
|
d.tmap[name] = ds
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return die
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
func walktypedef(die *dwarf.DWDie) *dwarf.DWDie {
|
|
|
|
|
if die == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
// Resolve typedef if present.
|
2016-07-28 13:04:41 -04:00
|
|
|
if die.Abbrev == dwarf.DW_ABRV_TYPEDECL {
|
|
|
|
|
for attr := die.Attr; attr != nil; attr = attr.Link {
|
|
|
|
|
if attr.Atr == dwarf.DW_AT_type && attr.Cls == dwarf.DW_CLS_REFERENCE && attr.Data != nil {
|
|
|
|
|
return attr.Data.(*dwarf.DWDie)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return die
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) walksymtypedef(symIdx loader.Sym) loader.Sym {
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
// We're being given the loader symbol for the type DIE, e.g.
|
2021-05-08 00:45:06 +07:00
|
|
|
// "go:info.type.uintptr". Map that first to the type symbol (e.g.
|
|
|
|
|
// "type:uintptr") and then to the typedef DIE for the type.
|
2019-11-20 10:43:11 -05:00
|
|
|
// FIXME: this seems clunky, maybe there is a better way to do this.
|
|
|
|
|
|
|
|
|
|
if ts, ok := d.rtmap[symIdx]; ok {
|
|
|
|
|
if def, ok := d.tdmap[ts]; ok {
|
|
|
|
|
return def
|
|
|
|
|
}
|
|
|
|
|
d.linkctxt.Errorf(ts, "internal error: no entry for sym %d in tdmap\n", ts)
|
|
|
|
|
return 0
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
d.linkctxt.Errorf(symIdx, "internal error: no entry for sym %d in rtmap\n", symIdx)
|
|
|
|
|
return 0
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
// Find child by AT_name using hashtable if available or linear scan
|
|
|
|
|
// if not.
|
2016-07-28 13:04:41 -04:00
|
|
|
func findchild(die *dwarf.DWDie, name string) *dwarf.DWDie {
|
|
|
|
|
var prev *dwarf.DWDie
|
2015-10-10 10:57:35 +00:00
|
|
|
for ; die != prev; prev, die = die, walktypedef(die) {
|
2016-07-28 13:04:41 -04:00
|
|
|
for a := die.Child; a != nil; a = a.Link {
|
|
|
|
|
if name == getattr(a, dwarf.DW_AT_name).Data {
|
2016-03-14 09:23:04 -07:00
|
|
|
return a
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2015-10-10 10:57:35 +00:00
|
|
|
}
|
2016-03-14 09:23:04 -07:00
|
|
|
continue
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// find looks up the loader symbol for the DWARF DIE generated for the
|
|
|
|
|
// type with the specified name.
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) find(name string) loader.Sym {
|
2019-11-20 10:43:11 -05:00
|
|
|
return d.tmap[name]
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) mustFind(name string) loader.Sym {
|
2019-11-20 10:43:11 -05:00
|
|
|
r := d.find(name)
|
|
|
|
|
if r == 0 {
|
2016-03-14 09:23:04 -07:00
|
|
|
Exitf("dwarf find: cannot find %s", name)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-01 09:27:46 -04:00
|
|
|
func (d *dwctxt) adddwarfref(sb *loader.SymbolBuilder, t loader.Sym, size int) {
|
2016-03-14 09:23:04 -07:00
|
|
|
switch size {
|
2015-02-27 22:57:28 -05:00
|
|
|
default:
|
2019-11-20 10:43:11 -05:00
|
|
|
d.linkctxt.Errorf(sb.Sym(), "invalid size %d in adddwarfref\n", size)
|
2020-03-28 16:46:47 -04:00
|
|
|
case d.arch.PtrSize, 4:
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2021-07-01 09:27:46 -04:00
|
|
|
sb.AddSymRef(d.arch, t, 0, objabi.R_DWARFSECREF, size)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-01 09:27:46 -04:00
|
|
|
func (d *dwctxt) newrefattr(die *dwarf.DWDie, attr uint16, ref loader.Sym) {
|
2019-11-20 10:43:11 -05:00
|
|
|
if ref == 0 {
|
2021-07-01 09:27:46 -04:00
|
|
|
return
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2021-07-01 09:27:46 -04:00
|
|
|
newattr(die, attr, dwarf.DW_CLS_REFERENCE, 0, dwSym(ref))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) dtolsym(s dwarf.Sym) loader.Sym {
|
2016-07-28 13:04:41 -04:00
|
|
|
if s == nil {
|
2019-11-20 10:43:11 -05:00
|
|
|
return 0
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2020-02-19 16:16:17 -05:00
|
|
|
dws := loader.Sym(s.(dwSym))
|
|
|
|
|
return dws
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) putdie(syms []loader.Sym, die *dwarf.DWDie) []loader.Sym {
|
2020-02-14 16:12:51 -05:00
|
|
|
s := d.dtolsym(die.Sym)
|
|
|
|
|
if s == 0 {
|
|
|
|
|
s = syms[len(syms)-1]
|
|
|
|
|
} else {
|
|
|
|
|
syms = append(syms, s)
|
|
|
|
|
}
|
|
|
|
|
sDwsym := dwSym(s)
|
|
|
|
|
dwarf.Uleb128put(d, sDwsym, int64(die.Abbrev))
|
|
|
|
|
dwarf.PutAttrs(d, sDwsym, die.Abbrev, die.Attr)
|
|
|
|
|
if dwarf.HasChildren(die) {
|
|
|
|
|
for die := die.Child; die != nil; die = die.Link {
|
|
|
|
|
syms = d.putdie(syms, die)
|
|
|
|
|
}
|
|
|
|
|
dsu := d.ldr.MakeSymbolUpdater(syms[len(syms)-1])
|
|
|
|
|
dsu.AddUint8(0)
|
|
|
|
|
}
|
|
|
|
|
return syms
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
func reverselist(list **dwarf.DWDie) {
|
2015-03-02 12:35:15 -05:00
|
|
|
curr := *list
|
2016-07-28 13:04:41 -04:00
|
|
|
var prev *dwarf.DWDie
|
2015-02-27 22:57:28 -05:00
|
|
|
for curr != nil {
|
2017-10-09 10:11:00 +01:00
|
|
|
next := curr.Link
|
2016-07-28 13:04:41 -04:00
|
|
|
curr.Link = prev
|
2015-02-27 22:57:28 -05:00
|
|
|
prev = curr
|
|
|
|
|
curr = next
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*list = prev
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
func reversetree(list **dwarf.DWDie) {
|
2015-02-27 22:57:28 -05:00
|
|
|
reverselist(list)
|
2016-07-28 13:04:41 -04:00
|
|
|
for die := *list; die != nil; die = die.Link {
|
|
|
|
|
if dwarf.HasChildren(die) {
|
|
|
|
|
reversetree(&die.Child)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
func newmemberoffsetattr(die *dwarf.DWDie, offs int32) {
|
2017-07-26 15:58:25 -04:00
|
|
|
newattr(die, dwarf.DW_AT_data_member_location, dwarf.DW_CLS_CONSTANT, int64(offs), nil)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) lookupOrDiag(n string) loader.Sym {
|
2019-11-20 10:43:11 -05:00
|
|
|
symIdx := d.ldr.Lookup(n, 0)
|
|
|
|
|
if symIdx == 0 {
|
2015-04-09 07:37:17 -04:00
|
|
|
Exitf("dwarf: missing type: %s", n)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
if len(d.ldr.Data(symIdx)) == 0 {
|
|
|
|
|
Exitf("dwarf: missing type (no data): %s", n)
|
2018-10-19 17:42:11 -04:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
return symIdx
|
2018-10-22 16:36:24 -04:00
|
|
|
}
|
|
|
|
|
|
2021-07-01 09:27:46 -04:00
|
|
|
func (d *dwctxt) dotypedef(parent *dwarf.DWDie, name string, def *dwarf.DWDie) *dwarf.DWDie {
|
2015-02-27 22:57:28 -05:00
|
|
|
// Only emit typedefs for real names.
|
|
|
|
|
if strings.HasPrefix(name, "map[") {
|
2018-09-10 15:36:59 +02:00
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
if strings.HasPrefix(name, "struct {") {
|
2018-09-10 15:36:59 +02:00
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2021-12-17 06:53:21 +00:00
|
|
|
// cmd/compile uses "noalg.struct {...}" as type name when hash and eq algorithm generation of
|
|
|
|
|
// this struct type is suppressed.
|
|
|
|
|
if strings.HasPrefix(name, "noalg.struct {") {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
if strings.HasPrefix(name, "chan ") {
|
2018-09-10 15:36:59 +02:00
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
if name[0] == '[' || name[0] == '*' {
|
2018-09-10 15:36:59 +02:00
|
|
|
return nil
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
if def == nil {
|
2016-09-17 09:39:33 -04:00
|
|
|
Errorf(nil, "dwarf: bad def in dotypedef")
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// Create a new loader symbol for the typedef. We no longer
|
|
|
|
|
// do lookups of typedef symbols by name, so this is going
|
|
|
|
|
// to be an anonymous symbol (we want this for perf reasons).
|
2020-03-24 12:08:36 -04:00
|
|
|
tds := d.ldr.CreateExtSym("", 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
tdsu := d.ldr.MakeSymbolUpdater(tds)
|
2020-05-20 13:51:59 -04:00
|
|
|
tdsu.SetType(sym.SDWARFTYPE)
|
2020-02-19 16:16:17 -05:00
|
|
|
def.Sym = dwSym(tds)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.ldr.SetAttrNotInSymbolTable(tds, true)
|
|
|
|
|
d.ldr.SetAttrReachable(tds, true)
|
2016-03-14 09:23:04 -07:00
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
// The typedef entry must be created after the def,
|
|
|
|
|
// so that future lookups will find the typedef instead
|
|
|
|
|
// of the real definition. This hooks the typedef into any
|
|
|
|
|
// circular definition loops, so that gdb can understand them.
|
2021-07-01 09:27:46 -04:00
|
|
|
die := d.newdie(parent, dwarf.DW_ABRV_TYPEDECL, name)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, tds)
|
2018-09-10 15:36:59 +02:00
|
|
|
|
|
|
|
|
return die
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Define gotype, for composite ones recurse into constituents.
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) defgotype(gotype loader.Sym) loader.Sym {
|
2019-11-20 10:43:11 -05:00
|
|
|
if gotype == 0 {
|
|
|
|
|
return d.mustFind("<unspecified>")
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// If we already have a tdmap entry for the gotype, return it.
|
|
|
|
|
if ds, ok := d.tdmap[gotype]; ok {
|
|
|
|
|
return ds
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
sn := d.ldr.SymName(gotype)
|
2021-05-08 00:45:06 +07:00
|
|
|
if !strings.HasPrefix(sn, "type:") {
|
|
|
|
|
d.linkctxt.Errorf(gotype, "dwarf: type name doesn't start with \"type:\"")
|
2019-11-20 10:43:11 -05:00
|
|
|
return d.mustFind("<unspecified>")
|
|
|
|
|
}
|
|
|
|
|
name := sn[5:] // could also decode from Type.string
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
sdie := d.find(name)
|
|
|
|
|
if sdie != 0 {
|
2016-03-14 09:23:04 -07:00
|
|
|
return sdie
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
gtdwSym := d.newtype(gotype)
|
2020-02-19 16:16:17 -05:00
|
|
|
d.tdmap[gotype] = loader.Sym(gtdwSym.Sym.(dwSym))
|
|
|
|
|
return loader.Sym(gtdwSym.Sym.(dwSym))
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie {
|
2019-11-20 10:43:11 -05:00
|
|
|
sn := d.ldr.SymName(gotype)
|
|
|
|
|
name := sn[5:] // could also decode from Type.string
|
|
|
|
|
tdata := d.ldr.Data(gotype)
|
2022-11-12 12:27:33 -05:00
|
|
|
if len(tdata) == 0 {
|
|
|
|
|
d.linkctxt.Errorf(gotype, "missing type")
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
kind := decodetypeKind(d.arch, tdata)
|
|
|
|
|
bytesize := decodetypeSize(d.arch, tdata)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2018-09-10 15:36:59 +02:00
|
|
|
var die, typedefdie *dwarf.DWDie
|
2024-04-01 15:39:41 -04:00
|
|
|
switch kind {
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Bool:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_boolean, 0)
|
|
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Int,
|
|
|
|
|
abi.Int8,
|
|
|
|
|
abi.Int16,
|
|
|
|
|
abi.Int32,
|
|
|
|
|
abi.Int64:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_signed, 0)
|
|
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Uint,
|
|
|
|
|
abi.Uint8,
|
|
|
|
|
abi.Uint16,
|
|
|
|
|
abi.Uint32,
|
|
|
|
|
abi.Uint64,
|
|
|
|
|
abi.Uintptr:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_unsigned, 0)
|
|
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Float32,
|
|
|
|
|
abi.Float64:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_float, 0)
|
|
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Complex64,
|
|
|
|
|
abi.Complex128:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_complex_float, 0)
|
|
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Array:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_ARRAYTYPE, name)
|
|
|
|
|
typedefdie = d.dotypedef(&dwtypes, name, die)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2020-04-29 17:34:46 -04:00
|
|
|
s := decodetypeArrayElem(d.ldr, d.arch, gotype)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
|
2021-07-01 09:27:46 -04:00
|
|
|
fld := d.newdie(die, dwarf.DW_ABRV_ARRAYRANGE, "range")
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// use actual length not upper bound; correct for 0-length arrays.
|
2020-04-29 17:34:46 -04:00
|
|
|
newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, decodetypeArrayLen(d.ldr, d.arch, gotype), 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Chan:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_CHANTYPE, name)
|
2020-04-29 17:34:46 -04:00
|
|
|
s := decodetypeChanElem(d.ldr, d.arch, gotype)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_go_elem, d.defgotype(s))
|
2016-03-14 09:23:04 -07:00
|
|
|
// Save elem type for synthesizechantypes. We could synthesize here
|
|
|
|
|
// but that would change the order of DIEs we output.
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, s)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Func:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_FUNCTYPE, name)
|
2017-08-14 15:07:57 -07:00
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2021-07-01 09:27:46 -04:00
|
|
|
typedefdie = d.dotypedef(&dwtypes, name, die)
|
2019-11-20 10:43:11 -05:00
|
|
|
data := d.ldr.Data(gotype)
|
|
|
|
|
// FIXME: add caching or reuse reloc slice.
|
|
|
|
|
relocs := d.ldr.Relocs(gotype)
|
|
|
|
|
nfields := decodetypeFuncInCount(d.arch, data)
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < nfields; i++ {
|
2020-04-29 17:34:46 -04:00
|
|
|
s := decodetypeFuncInType(d.ldr, d.arch, gotype, &relocs, i)
|
2019-11-20 10:43:11 -05:00
|
|
|
sn := d.ldr.SymName(s)
|
2021-07-01 09:27:46 -04:00
|
|
|
fld := d.newdie(die, dwarf.DW_ABRV_FUNCTYPEPARAM, sn[5:])
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
if decodetypeFuncDotdotdot(d.arch, data) {
|
2021-07-01 09:27:46 -04:00
|
|
|
d.newdie(die, dwarf.DW_ABRV_DOTDOTDOT, "...")
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
nfields = decodetypeFuncOutCount(d.arch, data)
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < nfields; i++ {
|
2020-04-29 17:34:46 -04:00
|
|
|
s := decodetypeFuncOutType(d.ldr, d.arch, gotype, &relocs, i)
|
2019-11-20 10:43:11 -05:00
|
|
|
sn := d.ldr.SymName(s)
|
2024-06-27 14:54:06 +00:00
|
|
|
fld := d.newdie(die, dwarf.DW_ABRV_FUNCTYPEOUTPARAM, sn[5:])
|
|
|
|
|
newattr(fld, dwarf.DW_AT_variable_parameter, dwarf.DW_CLS_FLAG, 1, 0)
|
|
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Interface:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_IFACETYPE, name)
|
|
|
|
|
typedefdie = d.dotypedef(&dwtypes, name, die)
|
2019-11-20 10:43:11 -05:00
|
|
|
data := d.ldr.Data(gotype)
|
|
|
|
|
nfields := int(decodetypeIfaceMethodCount(d.arch, data))
|
|
|
|
|
var s loader.Sym
|
2015-02-27 22:57:28 -05:00
|
|
|
if nfields == 0 {
|
2019-11-20 10:43:11 -05:00
|
|
|
s = d.typeRuntimeEface
|
2015-02-27 22:57:28 -05:00
|
|
|
} else {
|
2019-11-20 10:43:11 -05:00
|
|
|
s = d.typeRuntimeIface
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Map:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_MAPTYPE, name)
|
2020-04-29 17:34:46 -04:00
|
|
|
s := decodetypeMapKey(d.ldr, d.arch, gotype)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_go_key, d.defgotype(s))
|
2020-04-29 17:34:46 -04:00
|
|
|
s = decodetypeMapValue(d.ldr, d.arch, gotype)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_go_elem, d.defgotype(s))
|
2016-03-14 09:23:04 -07:00
|
|
|
// Save gotype for use in synthesizemaptypes. We could synthesize here,
|
|
|
|
|
// but that would change the order of the DIEs.
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, gotype)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Pointer:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_PTRTYPE, name)
|
|
|
|
|
typedefdie = d.dotypedef(&dwtypes, name, die)
|
2020-04-29 17:34:46 -04:00
|
|
|
s := decodetypePtrElem(d.ldr, d.arch, gotype)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Slice:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_SLICETYPE, name)
|
|
|
|
|
typedefdie = d.dotypedef(&dwtypes, name, die)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2020-04-29 17:34:46 -04:00
|
|
|
s := decodetypeArrayElem(d.ldr, d.arch, gotype)
|
2019-11-20 10:43:11 -05:00
|
|
|
elem := d.defgotype(s)
|
|
|
|
|
d.newrefattr(die, dwarf.DW_AT_go_elem, elem)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.String:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_STRINGTYPE, name)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.Struct:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_STRUCTTYPE, name)
|
|
|
|
|
typedefdie = d.dotypedef(&dwtypes, name, die)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2020-04-29 17:34:46 -04:00
|
|
|
nfields := decodetypeStructFieldCount(d.ldr, d.arch, gotype)
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < nfields; i++ {
|
2020-04-29 17:34:46 -04:00
|
|
|
f := decodetypeStructFieldName(d.ldr, d.arch, gotype, i)
|
|
|
|
|
s := decodetypeStructFieldType(d.ldr, d.arch, gotype, i)
|
2015-02-27 22:57:28 -05:00
|
|
|
if f == "" {
|
2019-11-20 10:43:11 -05:00
|
|
|
sn := d.ldr.SymName(s)
|
2021-05-08 00:45:06 +07:00
|
|
|
f = sn[5:] // skip "type:"
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2021-07-01 09:27:46 -04:00
|
|
|
fld := d.newdie(die, dwarf.DW_ABRV_STRUCTFIELD, f)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s))
|
2022-06-14 13:38:02 -07:00
|
|
|
offset := decodetypeStructFieldOffset(d.ldr, d.arch, gotype, i)
|
|
|
|
|
newmemberoffsetattr(fld, int32(offset))
|
|
|
|
|
if decodetypeStructFieldEmbedded(d.ldr, d.arch, gotype, i) {
|
2017-04-26 17:58:31 -04:00
|
|
|
newattr(fld, dwarf.DW_AT_go_embedded_field, dwarf.DW_CLS_FLAG, 1, 0)
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2024-04-02 13:08:24 +00:00
|
|
|
case abi.UnsafePointer:
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, name)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
default:
|
2019-11-20 10:43:11 -05:00
|
|
|
d.linkctxt.Errorf(gotype, "dwarf: definition of unknown kind %d", kind)
|
2021-07-01 09:27:46 -04:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_TYPEDECL, name)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, d.mustFind("<unspecified>"))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, int64(kind), 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
if d.ldr.AttrReachable(gotype) {
|
2020-02-19 16:16:17 -05:00
|
|
|
newattr(die, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_GO_TYPEREF, 0, dwSym(gotype))
|
2018-04-12 17:07:14 -04:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// Sanity check.
|
|
|
|
|
if _, ok := d.rtmap[gotype]; ok {
|
|
|
|
|
log.Fatalf("internal error: rtmap entry already installed\n")
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-19 16:16:17 -05:00
|
|
|
ds := loader.Sym(die.Sym.(dwSym))
|
2019-11-20 10:43:11 -05:00
|
|
|
if typedefdie != nil {
|
2020-02-19 16:16:17 -05:00
|
|
|
ds = loader.Sym(typedefdie.Sym.(dwSym))
|
2019-11-20 10:43:11 -05:00
|
|
|
}
|
2020-02-19 16:16:17 -05:00
|
|
|
d.rtmap[ds] = gotype
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
if _, ok := prototypedies[sn]; ok {
|
|
|
|
|
prototypedies[sn] = die
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
|
|
|
|
|
2018-09-10 15:36:59 +02:00
|
|
|
if typedefdie != nil {
|
|
|
|
|
return typedefdie
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
return die
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) nameFromDIESym(dwtypeDIESym loader.Sym) string {
|
2019-11-20 10:43:11 -05:00
|
|
|
sn := d.ldr.SymName(dwtypeDIESym)
|
|
|
|
|
return sn[len(dwarf.InfoPrefix):]
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) defptrto(dwtype loader.Sym) loader.Sym {
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
// FIXME: it would be nice if the compiler attached an aux symbol
|
|
|
|
|
// ref from the element type to the pointer type -- it would be
|
|
|
|
|
// more efficient to do it this way as opposed to via name lookups.
|
|
|
|
|
|
|
|
|
|
ptrname := "*" + d.nameFromDIESym(dwtype)
|
|
|
|
|
if die := d.find(ptrname); die != 0 {
|
2018-04-12 17:07:14 -04:00
|
|
|
return die
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-01 09:27:46 -04:00
|
|
|
pdie := d.newdie(&dwtypes, dwarf.DW_ABRV_PTRTYPE, ptrname)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(pdie, dwarf.DW_AT_type, dwtype)
|
2018-04-12 17:07:14 -04:00
|
|
|
|
|
|
|
|
// The DWARF info synthesizes pointer types that don't exist at the
|
|
|
|
|
// language level, like *hash<...> and *bucket<...>, and the data
|
|
|
|
|
// pointers of slices. Link to the ones we can find.
|
2021-05-08 00:45:06 +07:00
|
|
|
gts := d.ldr.Lookup("type:"+ptrname, 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
if gts != 0 && d.ldr.AttrReachable(gts) {
|
2024-04-02 13:08:24 +00:00
|
|
|
newattr(pdie, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, int64(abi.Pointer), 0)
|
2020-02-19 16:16:17 -05:00
|
|
|
newattr(pdie, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_GO_TYPEREF, 0, dwSym(gts))
|
2019-11-20 10:43:11 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if gts != 0 {
|
2020-02-19 16:16:17 -05:00
|
|
|
ds := loader.Sym(pdie.Sym.(dwSym))
|
|
|
|
|
d.rtmap[ds] = gts
|
|
|
|
|
d.tdmap[gts] = ds
|
2018-04-12 17:07:14 -04:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
return d.dtolsym(pdie.Sym)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copies src's children into dst. Copies attributes by value.
|
2016-03-01 23:21:55 +00:00
|
|
|
// DWAttr.data is copied as pointer only. If except is one of
|
2015-02-27 22:57:28 -05:00
|
|
|
// the top-level children, it will not be copied.
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) copychildrenexcept(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie, except *dwarf.DWDie) {
|
2016-07-28 13:04:41 -04:00
|
|
|
for src = src.Child; src != nil; src = src.Link {
|
2015-02-27 22:57:28 -05:00
|
|
|
if src == except {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-07-01 09:27:46 -04:00
|
|
|
c := d.newdie(dst, src.Abbrev, getattr(src, dwarf.DW_AT_name).Data.(string))
|
2016-07-28 13:04:41 -04:00
|
|
|
for a := src.Attr; a != nil; a = a.Link {
|
|
|
|
|
newattr(c, a.Atr, int(a.Cls), a.Value, a.Data)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
d.copychildrenexcept(ctxt, c, src, nil)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
reverselist(&dst.Child)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) copychildren(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie) {
|
2019-11-20 10:43:11 -05:00
|
|
|
d.copychildrenexcept(ctxt, dst, src, nil)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
// Search children (assumed to have TAG_member) for the one named
|
|
|
|
|
// field and set its AT_type to dwtype
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) substitutetype(structdie *dwarf.DWDie, field string, dwtype loader.Sym) {
|
2016-03-14 09:23:04 -07:00
|
|
|
child := findchild(structdie, field)
|
2015-02-27 22:57:28 -05:00
|
|
|
if child == nil {
|
2016-03-14 09:23:04 -07:00
|
|
|
Exitf("dwarf substitutetype: %s does not have member %s",
|
2016-07-28 13:04:41 -04:00
|
|
|
getattr(structdie, dwarf.DW_AT_name).Data, field)
|
2015-02-27 22:57:28 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
a := getattr(child, dwarf.DW_AT_type)
|
2015-02-27 22:57:28 -05:00
|
|
|
if a != nil {
|
2020-02-19 16:16:17 -05:00
|
|
|
a.Data = dwSym(dwtype)
|
2015-02-27 22:57:28 -05:00
|
|
|
} else {
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(child, dwarf.DW_AT_type, dwtype)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) findprotodie(ctxt *Link, name string) *dwarf.DWDie {
|
2016-03-14 09:23:04 -07:00
|
|
|
die, ok := prototypedies[name]
|
|
|
|
|
if ok && die == nil {
|
2019-11-20 10:43:11 -05:00
|
|
|
d.defgotype(d.lookupOrDiag(name))
|
2016-03-14 09:23:04 -07:00
|
|
|
die = prototypedies[name]
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
if die == nil {
|
2024-05-03 13:03:04 -04:00
|
|
|
log.Fatalf("internal error: DIE generation failed for %s\nprototypedies: %+v", name, prototypedies)
|
2019-11-20 10:43:11 -05:00
|
|
|
}
|
2016-03-14 09:23:04 -07:00
|
|
|
return die
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) synthesizestringtypes(ctxt *Link, die *dwarf.DWDie) {
|
2021-05-08 00:45:06 +07:00
|
|
|
prototype := walktypedef(d.findprotodie(ctxt, "type:runtime.stringStructDWARF"))
|
2015-02-27 22:57:28 -05:00
|
|
|
if prototype == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
for ; die != nil; die = die.Link {
|
|
|
|
|
if die.Abbrev != dwarf.DW_ABRV_STRINGTYPE {
|
2015-02-27 22:57:28 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
d.copychildren(ctxt, die, prototype)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) synthesizeslicetypes(ctxt *Link, die *dwarf.DWDie) {
|
2021-05-08 00:45:06 +07:00
|
|
|
prototype := walktypedef(d.findprotodie(ctxt, "type:runtime.slice"))
|
2015-02-27 22:57:28 -05:00
|
|
|
if prototype == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
for ; die != nil; die = die.Link {
|
|
|
|
|
if die.Abbrev != dwarf.DW_ABRV_SLICETYPE {
|
2015-02-27 22:57:28 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
d.copychildren(ctxt, die, prototype)
|
2020-02-19 16:16:17 -05:00
|
|
|
elem := loader.Sym(getattr(die, dwarf.DW_AT_go_elem).Data.(dwSym))
|
2019-11-20 10:43:11 -05:00
|
|
|
d.substitutetype(die, "array", d.defptrto(elem))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mkinternaltypename(base string, arg1 string, arg2 string) string {
|
|
|
|
|
if arg2 == "" {
|
2018-04-06 21:41:06 +01:00
|
|
|
return fmt.Sprintf("%s<%s>", base, arg1)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2018-04-06 21:41:06 +01:00
|
|
|
return fmt.Sprintf("%s<%s,%s>", base, arg1, arg2)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) mkinternaltype(ctxt *Link, abbrev int, typename, keyname, valname string, f func(*dwarf.DWDie)) loader.Sym {
|
2016-03-14 09:23:04 -07:00
|
|
|
name := mkinternaltypename(typename, keyname, valname)
|
2016-07-28 13:04:41 -04:00
|
|
|
symname := dwarf.InfoPrefix + name
|
2019-11-20 10:43:11 -05:00
|
|
|
s := d.ldr.Lookup(symname, 0)
|
2020-05-20 13:51:59 -04:00
|
|
|
if s != 0 && d.ldr.SymType(s) == sym.SDWARFTYPE {
|
2016-03-14 09:23:04 -07:00
|
|
|
return s
|
|
|
|
|
}
|
2021-07-01 09:27:46 -04:00
|
|
|
die := d.newdie(&dwtypes, abbrev, name)
|
2016-03-14 09:23:04 -07:00
|
|
|
f(die)
|
2019-11-20 10:43:11 -05:00
|
|
|
return d.dtolsym(die.Sym)
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
|
2024-04-19 13:52:31 -04:00
|
|
|
if buildcfg.Experiment.SwissMap {
|
|
|
|
|
d.synthesizemaptypesSwiss(ctxt, die)
|
|
|
|
|
} else {
|
|
|
|
|
d.synthesizemaptypesOld(ctxt, die)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *dwctxt) synthesizemaptypesSwiss(ctxt *Link, die *dwarf.DWDie) {
|
2024-05-03 13:03:04 -04:00
|
|
|
hash := walktypedef(d.findprotodie(ctxt, "type:internal/runtime/maps.table"))
|
|
|
|
|
//bucket := walktypedef(d.findprotodie(ctxt, "type:internal/runtime/maps.Map"))
|
2024-04-19 13:52:31 -04:00
|
|
|
|
|
|
|
|
if hash == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ; die != nil; die = die.Link {
|
|
|
|
|
if die.Abbrev != dwarf.DW_ABRV_MAPTYPE {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
gotype := loader.Sym(getattr(die, dwarf.DW_AT_type).Data.(dwSym))
|
|
|
|
|
keytype := decodetypeMapKey(d.ldr, d.arch, gotype)
|
|
|
|
|
valtype := decodetypeMapValue(d.ldr, d.arch, gotype)
|
2024-05-03 13:03:04 -04:00
|
|
|
//keydata := d.ldr.Data(keytype)
|
|
|
|
|
//valdata := d.ldr.Data(valtype)
|
|
|
|
|
//keysize, valsize := decodetypeSize(d.arch, keydata), decodetypeSize(d.arch, valdata)
|
2024-04-19 13:52:31 -04:00
|
|
|
keytype, valtype = d.walksymtypedef(d.defgotype(keytype)), d.walksymtypedef(d.defgotype(valtype))
|
|
|
|
|
|
|
|
|
|
// compute size info like hashmap.c does.
|
2024-05-03 13:03:04 -04:00
|
|
|
//indirectKey, indirectVal := false, false
|
|
|
|
|
//if keysize > abi.SwissMapMaxKeyBytes {
|
|
|
|
|
// keysize = int64(d.arch.PtrSize)
|
|
|
|
|
// indirectKey = true
|
|
|
|
|
//}
|
|
|
|
|
//if valsize > abi.SwissMapMaxElemBytes {
|
|
|
|
|
// valsize = int64(d.arch.PtrSize)
|
|
|
|
|
// indirectVal = true
|
|
|
|
|
//}
|
2024-04-19 13:52:31 -04:00
|
|
|
|
|
|
|
|
// Construct type to represent an array of BucketSize keys
|
2024-05-03 13:03:04 -04:00
|
|
|
// TODO
|
2024-04-19 13:52:31 -04:00
|
|
|
keyname := d.nameFromDIESym(keytype)
|
2024-05-03 13:03:04 -04:00
|
|
|
//dwhks := d.mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *dwarf.DWDie) {
|
|
|
|
|
// newattr(dwhk, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, abi.SwissMapBucketCount*keysize, 0)
|
|
|
|
|
// t := keytype
|
|
|
|
|
// if indirectKey {
|
|
|
|
|
// t = d.defptrto(keytype)
|
|
|
|
|
// }
|
|
|
|
|
// d.newrefattr(dwhk, dwarf.DW_AT_type, t)
|
|
|
|
|
// fld := d.newdie(dwhk, dwarf.DW_ABRV_ARRAYRANGE, "size")
|
|
|
|
|
// newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, abi.SwissMapBucketCount, 0)
|
|
|
|
|
// d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
|
|
|
|
|
//})
|
2024-04-19 13:52:31 -04:00
|
|
|
|
|
|
|
|
// Construct type to represent an array of BucketSize values
|
2024-05-03 13:03:04 -04:00
|
|
|
// TODO
|
2024-04-19 13:52:31 -04:00
|
|
|
valname := d.nameFromDIESym(valtype)
|
2024-05-03 13:03:04 -04:00
|
|
|
//dwhvs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *dwarf.DWDie) {
|
|
|
|
|
// newattr(dwhv, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, abi.SwissMapBucketCount*valsize, 0)
|
|
|
|
|
// t := valtype
|
|
|
|
|
// if indirectVal {
|
|
|
|
|
// t = d.defptrto(valtype)
|
|
|
|
|
// }
|
|
|
|
|
// d.newrefattr(dwhv, dwarf.DW_AT_type, t)
|
|
|
|
|
// fld := d.newdie(dwhv, dwarf.DW_ABRV_ARRAYRANGE, "size")
|
|
|
|
|
// newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, abi.SwissMapBucketCount, 0)
|
|
|
|
|
// d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
|
|
|
|
|
//})
|
2024-04-19 13:52:31 -04:00
|
|
|
|
|
|
|
|
// Construct bucket<K,V>
|
2024-05-03 13:03:04 -04:00
|
|
|
// TODO
|
|
|
|
|
//dwhbs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *dwarf.DWDie) {
|
|
|
|
|
// // Copy over all fields except the field "data" from the generic
|
|
|
|
|
// // bucket. "data" will be replaced with keys/values below.
|
|
|
|
|
// d.copychildrenexcept(ctxt, dwhb, bucket, findchild(bucket, "data"))
|
|
|
|
|
|
|
|
|
|
// fld := d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "keys")
|
|
|
|
|
// d.newrefattr(fld, dwarf.DW_AT_type, dwhks)
|
|
|
|
|
// newmemberoffsetattr(fld, abi.SwissMapBucketCount)
|
|
|
|
|
// fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "values")
|
|
|
|
|
// d.newrefattr(fld, dwarf.DW_AT_type, dwhvs)
|
|
|
|
|
// newmemberoffsetattr(fld, abi.SwissMapBucketCount+abi.SwissMapBucketCount*int32(keysize))
|
|
|
|
|
// fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "overflow")
|
|
|
|
|
// d.newrefattr(fld, dwarf.DW_AT_type, d.defptrto(d.dtolsym(dwhb.Sym)))
|
|
|
|
|
// newmemberoffsetattr(fld, abi.SwissMapBucketCount+abi.SwissMapBucketCount*(int32(keysize)+int32(valsize)))
|
|
|
|
|
// if d.arch.RegSize > d.arch.PtrSize {
|
|
|
|
|
// fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "pad")
|
|
|
|
|
// d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
|
|
|
|
|
// newmemberoffsetattr(fld, abi.SwissMapBucketCount+abi.SwissMapBucketCount*(int32(keysize)+int32(valsize))+int32(d.arch.PtrSize))
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// newattr(dwhb, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, abi.SwissMapBucketCount+abi.SwissMapBucketCount*keysize+abi.SwissMapBucketCount*valsize+int64(d.arch.RegSize), 0)
|
|
|
|
|
//})
|
2024-04-19 13:52:31 -04:00
|
|
|
|
|
|
|
|
// Construct hash<K,V>
|
|
|
|
|
dwhs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *dwarf.DWDie) {
|
|
|
|
|
d.copychildren(ctxt, dwh, hash)
|
2024-05-03 13:03:04 -04:00
|
|
|
//d.substitutetype(dwh, "buckets", d.defptrto(dwhbs))
|
|
|
|
|
//d.substitutetype(dwh, "oldbuckets", d.defptrto(dwhbs))
|
2024-04-19 13:52:31 -04:00
|
|
|
newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(hash, dwarf.DW_AT_byte_size).Value, nil)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// make map type a pointer to hash<K,V>
|
|
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, d.defptrto(dwhs))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *dwctxt) synthesizemaptypesOld(ctxt *Link, die *dwarf.DWDie) {
|
2021-05-08 00:45:06 +07:00
|
|
|
hash := walktypedef(d.findprotodie(ctxt, "type:runtime.hmap"))
|
|
|
|
|
bucket := walktypedef(d.findprotodie(ctxt, "type:runtime.bmap"))
|
2015-03-02 12:35:15 -05:00
|
|
|
|
|
|
|
|
if hash == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
for ; die != nil; die = die.Link {
|
|
|
|
|
if die.Abbrev != dwarf.DW_ABRV_MAPTYPE {
|
2015-02-27 22:57:28 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2020-02-19 16:16:17 -05:00
|
|
|
gotype := loader.Sym(getattr(die, dwarf.DW_AT_type).Data.(dwSym))
|
2020-04-29 17:34:46 -04:00
|
|
|
keytype := decodetypeMapKey(d.ldr, d.arch, gotype)
|
|
|
|
|
valtype := decodetypeMapValue(d.ldr, d.arch, gotype)
|
2019-11-20 10:43:11 -05:00
|
|
|
keydata := d.ldr.Data(keytype)
|
|
|
|
|
valdata := d.ldr.Data(valtype)
|
|
|
|
|
keysize, valsize := decodetypeSize(d.arch, keydata), decodetypeSize(d.arch, valdata)
|
|
|
|
|
keytype, valtype = d.walksymtypedef(d.defgotype(keytype)), d.walksymtypedef(d.defgotype(valtype))
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// compute size info like hashmap.c does.
|
2016-08-22 10:33:13 -04:00
|
|
|
indirectKey, indirectVal := false, false
|
2024-04-19 13:52:31 -04:00
|
|
|
if keysize > abi.OldMapMaxKeyBytes {
|
2019-11-20 10:43:11 -05:00
|
|
|
keysize = int64(d.arch.PtrSize)
|
2016-08-22 10:33:13 -04:00
|
|
|
indirectKey = true
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2024-04-19 13:52:31 -04:00
|
|
|
if valsize > abi.OldMapMaxElemBytes {
|
2019-11-20 10:43:11 -05:00
|
|
|
valsize = int64(d.arch.PtrSize)
|
2016-08-22 10:33:13 -04:00
|
|
|
indirectVal = true
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Construct type to represent an array of BucketSize keys
|
2019-11-20 10:43:11 -05:00
|
|
|
keyname := d.nameFromDIESym(keytype)
|
|
|
|
|
dwhks := d.mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *dwarf.DWDie) {
|
2024-04-19 13:52:31 -04:00
|
|
|
newattr(dwhk, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, abi.OldMapBucketCount*keysize, 0)
|
2016-03-14 09:23:04 -07:00
|
|
|
t := keytype
|
2016-08-22 10:33:13 -04:00
|
|
|
if indirectKey {
|
2019-11-20 10:43:11 -05:00
|
|
|
t = d.defptrto(keytype)
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(dwhk, dwarf.DW_AT_type, t)
|
2021-07-01 09:27:46 -04:00
|
|
|
fld := d.newdie(dwhk, dwarf.DW_ABRV_ARRAYRANGE, "size")
|
2024-04-19 13:52:31 -04:00
|
|
|
newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, abi.OldMapBucketCount, 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
|
2016-03-14 09:23:04 -07:00
|
|
|
})
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// Construct type to represent an array of BucketSize values
|
2019-11-20 10:43:11 -05:00
|
|
|
valname := d.nameFromDIESym(valtype)
|
|
|
|
|
dwhvs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *dwarf.DWDie) {
|
2024-04-19 13:52:31 -04:00
|
|
|
newattr(dwhv, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, abi.OldMapBucketCount*valsize, 0)
|
2016-03-14 09:23:04 -07:00
|
|
|
t := valtype
|
2016-08-22 10:33:13 -04:00
|
|
|
if indirectVal {
|
2019-11-20 10:43:11 -05:00
|
|
|
t = d.defptrto(valtype)
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(dwhv, dwarf.DW_AT_type, t)
|
2021-07-01 09:27:46 -04:00
|
|
|
fld := d.newdie(dwhv, dwarf.DW_ABRV_ARRAYRANGE, "size")
|
2024-04-19 13:52:31 -04:00
|
|
|
newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, abi.OldMapBucketCount, 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
|
2016-03-14 09:23:04 -07:00
|
|
|
})
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// Construct bucket<K,V>
|
2019-11-20 10:43:11 -05:00
|
|
|
dwhbs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *dwarf.DWDie) {
|
2016-03-14 09:23:04 -07:00
|
|
|
// Copy over all fields except the field "data" from the generic
|
|
|
|
|
// bucket. "data" will be replaced with keys/values below.
|
2019-11-20 10:43:11 -05:00
|
|
|
d.copychildrenexcept(ctxt, dwhb, bucket, findchild(bucket, "data"))
|
2016-03-14 09:23:04 -07:00
|
|
|
|
2021-07-01 09:27:46 -04:00
|
|
|
fld := d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "keys")
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, dwhks)
|
2024-04-19 13:52:31 -04:00
|
|
|
newmemberoffsetattr(fld, abi.OldMapBucketCount)
|
2021-07-01 09:27:46 -04:00
|
|
|
fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "values")
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, dwhvs)
|
2024-04-19 13:52:31 -04:00
|
|
|
newmemberoffsetattr(fld, abi.OldMapBucketCount+abi.OldMapBucketCount*int32(keysize))
|
2021-07-01 09:27:46 -04:00
|
|
|
fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "overflow")
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.defptrto(d.dtolsym(dwhb.Sym)))
|
2024-04-19 13:52:31 -04:00
|
|
|
newmemberoffsetattr(fld, abi.OldMapBucketCount+abi.OldMapBucketCount*(int32(keysize)+int32(valsize)))
|
2019-11-20 10:43:11 -05:00
|
|
|
if d.arch.RegSize > d.arch.PtrSize {
|
2021-07-01 09:27:46 -04:00
|
|
|
fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "pad")
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
|
2024-04-19 13:52:31 -04:00
|
|
|
newmemberoffsetattr(fld, abi.OldMapBucketCount+abi.OldMapBucketCount*(int32(keysize)+int32(valsize))+int32(d.arch.PtrSize))
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2024-04-19 13:52:31 -04:00
|
|
|
newattr(dwhb, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, abi.OldMapBucketCount+abi.OldMapBucketCount*keysize+abi.OldMapBucketCount*valsize+int64(d.arch.RegSize), 0)
|
2016-03-14 09:23:04 -07:00
|
|
|
})
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// Construct hash<K,V>
|
2019-11-20 10:43:11 -05:00
|
|
|
dwhs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *dwarf.DWDie) {
|
|
|
|
|
d.copychildren(ctxt, dwh, hash)
|
|
|
|
|
d.substitutetype(dwh, "buckets", d.defptrto(dwhbs))
|
|
|
|
|
d.substitutetype(dwh, "oldbuckets", d.defptrto(dwhbs))
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(hash, dwarf.DW_AT_byte_size).Value, nil)
|
2016-03-14 09:23:04 -07:00
|
|
|
})
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// make map type a pointer to hash<K,V>
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, d.defptrto(dwhs))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) synthesizechantypes(ctxt *Link, die *dwarf.DWDie) {
|
2021-05-08 00:45:06 +07:00
|
|
|
sudog := walktypedef(d.findprotodie(ctxt, "type:runtime.sudog"))
|
|
|
|
|
waitq := walktypedef(d.findprotodie(ctxt, "type:runtime.waitq"))
|
|
|
|
|
hchan := walktypedef(d.findprotodie(ctxt, "type:runtime.hchan"))
|
2015-02-27 22:57:28 -05:00
|
|
|
if sudog == nil || waitq == nil || hchan == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
sudogsize := int(getattr(sudog, dwarf.DW_AT_byte_size).Value)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
for ; die != nil; die = die.Link {
|
|
|
|
|
if die.Abbrev != dwarf.DW_ABRV_CHANTYPE {
|
2015-02-27 22:57:28 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2020-02-19 16:16:17 -05:00
|
|
|
elemgotype := loader.Sym(getattr(die, dwarf.DW_AT_type).Data.(dwSym))
|
2019-11-20 10:43:11 -05:00
|
|
|
tname := d.ldr.SymName(elemgotype)
|
|
|
|
|
elemname := tname[5:]
|
|
|
|
|
elemtype := d.walksymtypedef(d.defgotype(d.lookupOrDiag(tname)))
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// sudog<T>
|
2019-11-20 10:43:11 -05:00
|
|
|
dwss := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "sudog", elemname, "", func(dws *dwarf.DWDie) {
|
|
|
|
|
d.copychildren(ctxt, dws, sudog)
|
|
|
|
|
d.substitutetype(dws, "elem", d.defptrto(elemtype))
|
2017-07-19 19:52:29 -07:00
|
|
|
newattr(dws, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(sudogsize), nil)
|
2016-03-14 09:23:04 -07:00
|
|
|
})
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// waitq<T>
|
2019-11-20 10:43:11 -05:00
|
|
|
dwws := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "waitq", elemname, "", func(dww *dwarf.DWDie) {
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
d.copychildren(ctxt, dww, waitq)
|
|
|
|
|
d.substitutetype(dww, "first", d.defptrto(dwss))
|
|
|
|
|
d.substitutetype(dww, "last", d.defptrto(dwss))
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(dww, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(waitq, dwarf.DW_AT_byte_size).Value, nil)
|
2016-03-14 09:23:04 -07:00
|
|
|
})
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// hchan<T>
|
2019-11-20 10:43:11 -05:00
|
|
|
dwhs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hchan", elemname, "", func(dwh *dwarf.DWDie) {
|
|
|
|
|
d.copychildren(ctxt, dwh, hchan)
|
|
|
|
|
d.substitutetype(dwh, "recvq", dwws)
|
|
|
|
|
d.substitutetype(dwh, "sendq", dwws)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(hchan, dwarf.DW_AT_byte_size).Value, nil)
|
2016-03-14 09:23:04 -07:00
|
|
|
})
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, d.defptrto(dwhs))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-28 16:44:30 +02:00
|
|
|
// createUnitLength creates the initial length field with value v and update
|
|
|
|
|
// offset of unit_length if needed.
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) createUnitLength(su *loader.SymbolBuilder, v uint64) {
|
2020-02-14 16:12:51 -05:00
|
|
|
if isDwarf64(d.linkctxt) {
|
|
|
|
|
su.AddUint32(d.arch, 0xFFFFFFFF)
|
|
|
|
|
}
|
|
|
|
|
d.addDwarfAddrField(su, v)
|
2018-09-28 16:44:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// addDwarfAddrField adds a DWARF field in DWARF 64bits or 32bits.
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) addDwarfAddrField(sb *loader.SymbolBuilder, v uint64) {
|
2020-02-14 16:12:51 -05:00
|
|
|
if isDwarf64(d.linkctxt) {
|
|
|
|
|
sb.AddUint(d.arch, v)
|
|
|
|
|
} else {
|
|
|
|
|
sb.AddUint32(d.arch, uint32(v))
|
|
|
|
|
}
|
2018-09-28 16:44:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// addDwarfAddrRef adds a DWARF pointer in DWARF 64bits or 32bits.
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) addDwarfAddrRef(sb *loader.SymbolBuilder, t loader.Sym) {
|
2020-02-14 16:12:51 -05:00
|
|
|
if isDwarf64(d.linkctxt) {
|
|
|
|
|
d.adddwarfref(sb, t, 8)
|
|
|
|
|
} else {
|
|
|
|
|
d.adddwarfref(sb, t, 4)
|
|
|
|
|
}
|
2018-09-28 16:44:30 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-24 13:05:10 +02:00
|
|
|
// calcCompUnitRanges calculates the PC ranges of the compilation units.
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) calcCompUnitRanges() {
|
2020-02-14 16:12:51 -05:00
|
|
|
var prevUnit *sym.CompilationUnit
|
2020-05-15 18:35:05 -04:00
|
|
|
for _, s := range d.linkctxt.Textp {
|
2020-02-14 16:12:51 -05:00
|
|
|
sym := loader.Sym(s)
|
|
|
|
|
|
|
|
|
|
fi := d.ldr.FuncInfo(sym)
|
|
|
|
|
if !fi.Valid() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip linker-created functions (ex: runtime.addmoduledata), since they
|
|
|
|
|
// don't have DWARF to begin with.
|
|
|
|
|
unit := d.ldr.SymUnit(sym)
|
|
|
|
|
if unit == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update PC ranges.
|
|
|
|
|
//
|
|
|
|
|
// We don't simply compare the end of the previous
|
|
|
|
|
// symbol with the start of the next because there's
|
|
|
|
|
// often a little padding between them. Instead, we
|
|
|
|
|
// only create boundaries between symbols from
|
|
|
|
|
// different units.
|
|
|
|
|
sval := d.ldr.SymValue(sym)
|
2020-05-15 18:35:05 -04:00
|
|
|
u0val := d.ldr.SymValue(loader.Sym(unit.Textp[0]))
|
2020-02-14 16:12:51 -05:00
|
|
|
if prevUnit != unit {
|
|
|
|
|
unit.PCs = append(unit.PCs, dwarf.Range{Start: sval - u0val})
|
|
|
|
|
prevUnit = unit
|
|
|
|
|
}
|
|
|
|
|
unit.PCs[len(unit.PCs)-1].End = sval - u0val + int64(len(d.ldr.Data(sym)))
|
|
|
|
|
}
|
cmd/link: one DWARF compilation unit per package
Currently, the linker generates one huge DWARF compilation unit for
the entire Go binary. This commit creates a separate compilation unit
and line table per Go package.
We temporarily lose compilation unit PC range information, since it's
now discontiguous, so harder to emit. We'll bring it back in the next
commit.
Beyond being "more traditional", this has various technical
advantages:
* It should speed up line table lookup, since that requires a
sequential scan of the line table. With this change, a debugger can
first locate the per-package line table and then scan only that line
table.
* Once we emit compilation unit PC ranges again, this should also
speed up various other debugger reverse PC lookups.
* It puts us in a good position to move more DWARF generation into the
compiler, which could produce at least the CU header, per-function
line table fragments, and per-function frame unwinding info that the
linker could simply paste together.
* It will let us record a per-package compiler command-line flags
(#22168).
Change-Id: Ibac642890984636b3ef1d4b37fe97f4453c2cc84
Reviewed-on: https://go-review.googlesource.com/69973
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-10-09 16:19:56 -04:00
|
|
|
}
|
|
|
|
|
|
2018-09-25 11:52:24 +02:00
|
|
|
func movetomodule(ctxt *Link, parent *dwarf.DWDie) {
|
2019-08-09 11:36:03 -04:00
|
|
|
die := ctxt.runtimeCU.DWInfo.Child
|
2016-07-28 13:04:41 -04:00
|
|
|
if die == nil {
|
2019-08-09 11:36:03 -04:00
|
|
|
ctxt.runtimeCU.DWInfo.Child = parent.Child
|
2016-07-28 13:04:41 -04:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
for die.Link != nil {
|
|
|
|
|
die = die.Link
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-07-28 13:04:41 -04:00
|
|
|
die.Link = parent.Child
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2016-10-07 15:06:09 +11:00
|
|
|
* Generate a sequence of opcodes that is as short as possible.
|
2015-02-27 22:57:28 -05:00
|
|
|
* See section 6.2.5
|
|
|
|
|
*/
|
|
|
|
|
const (
|
2016-10-07 15:06:09 +11:00
|
|
|
LINE_BASE = -4
|
|
|
|
|
LINE_RANGE = 10
|
|
|
|
|
PC_RANGE = (255 - OPCODE_BASE) / LINE_RANGE
|
2018-04-30 23:52:14 -04:00
|
|
|
OPCODE_BASE = 11
|
2015-02-27 22:57:28 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Walk prog table, emit line program and build DIE tree.
|
|
|
|
|
*/
|
|
|
|
|
|
2015-04-08 12:55:34 -07:00
|
|
|
func getCompilationDir() string {
|
2017-11-16 16:19:19 -05:00
|
|
|
// OSX requires this be set to something, but it's not easy to choose
|
|
|
|
|
// a value. Linking takes place in a temporary directory, so there's
|
|
|
|
|
// no point including it here. Paths in the file table are usually
|
|
|
|
|
// absolute, in which case debuggers will ignore this value. -trimpath
|
|
|
|
|
// produces relative paths, but we don't know where they start, so
|
|
|
|
|
// all we can do here is try not to make things worse.
|
|
|
|
|
return "."
|
2015-04-08 12:55:34 -07:00
|
|
|
}
|
|
|
|
|
|
2020-05-20 15:06:22 -04:00
|
|
|
func (d *dwctxt) importInfoSymbol(dsym loader.Sym) {
|
2019-11-20 10:43:11 -05:00
|
|
|
d.ldr.SetAttrReachable(dsym, true)
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(dsym, true)
|
2020-05-20 13:51:59 -04:00
|
|
|
dst := d.ldr.SymType(dsym)
|
|
|
|
|
if dst != sym.SDWARFCONST && dst != sym.SDWARFABSFCN {
|
2019-11-20 10:43:11 -05:00
|
|
|
log.Fatalf("error: DWARF info sym %d/%s with incorrect type %s", dsym, d.ldr.SymName(dsym), d.ldr.SymType(dsym).String())
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2020-03-16 12:09:52 -04:00
|
|
|
relocs := d.ldr.Relocs(dsym)
|
2020-03-30 10:04:00 -04:00
|
|
|
for i := 0; i < relocs.Count(); i++ {
|
2020-07-29 13:26:50 -04:00
|
|
|
r := relocs.At(i)
|
2020-03-16 12:09:52 -04:00
|
|
|
if r.Type() != objabi.R_DWARFSECREF {
|
2019-11-20 10:43:11 -05:00
|
|
|
continue
|
2018-02-13 17:39:38 -05:00
|
|
|
}
|
2020-03-16 12:09:52 -04:00
|
|
|
rsym := r.Sym()
|
2019-11-20 10:43:11 -05:00
|
|
|
// If there is an entry for the symbol in our rtmap, then it
|
|
|
|
|
// means we've processed the type already, and can skip this one.
|
2020-03-16 12:09:52 -04:00
|
|
|
if _, ok := d.rtmap[rsym]; ok {
|
2019-11-20 10:43:11 -05:00
|
|
|
// type already generated
|
|
|
|
|
continue
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
// FIXME: is there a way we could avoid materializing the
|
|
|
|
|
// symbol name here?
|
2020-03-16 12:09:52 -04:00
|
|
|
sn := d.ldr.SymName(rsym)
|
2019-11-20 10:43:11 -05:00
|
|
|
tn := sn[len(dwarf.InfoPrefix):]
|
2021-05-08 00:45:06 +07:00
|
|
|
ts := d.ldr.Lookup("type:"+tn, 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.defgotype(ts)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2020-02-14 16:12:51 -05:00
|
|
|
func expandFile(fname string) string {
|
2023-11-01 15:34:27 +00:00
|
|
|
fname = strings.TrimPrefix(fname, src.FileSymPrefix)
|
2020-02-14 16:12:51 -05:00
|
|
|
return expandGoroot(fname)
|
|
|
|
|
}
|
|
|
|
|
|
cmd/link: emit include directories in DWARF line table prologue
This patch changes the way the linker emits the DWARF line table
prologue, specifically the file table. Previously files were left
unmodified, and the directory table was empty. For each compilation
unit we now scan the unit file table and build up a common set of
directories, emit them into the directory table, and then emit file
entries that refer to the dirs. This provides a modest binary size
savings.
For kubernetes kubelet:
$ objdump -h /tmp/kubelet.old | fgrep debug_line
36 .zdebug_line 019a55f5 0000000000000000 0000000000000000 084a5123 2**0
$ objdump -h /tmp/kubelet.new | fgrep debug_line
36 .zdebug_line 01146fd2 0000000000000000 0000000000000000 084a510a 2**0
[where the value following the section name above is the section size
in hex, so roughly a 30% decrease in this case.]
The actual savings will depend on the length of the pathnames
involved, so it's hard to really pin down how much savings we'll see
here. In addition, emitting the files this way reduces the
"compressibility" of the line table, so there could even be cases
where we don't win at all.
Updates #6853, #19784, #36495.
Change-Id: I298d8561da5ed3ebc9d38aa772874851baa2f4f4
Reviewed-on: https://go-review.googlesource.com/c/go/+/263017
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Trust: Than McIntosh <thanm@google.com>
2020-10-16 09:22:31 -04:00
|
|
|
// writeDirFileTables emits the portion of the DWARF line table
|
|
|
|
|
// prologue containing the include directories and file names,
|
|
|
|
|
// described in section 6.2.4 of the DWARF 4 standard. It walks the
|
|
|
|
|
// filepaths for the unit to discover any common directories, which
|
|
|
|
|
// are emitted to the directory table first, then the file table is
|
|
|
|
|
// emitted after that.
|
|
|
|
|
func (d *dwctxt) writeDirFileTables(unit *sym.CompilationUnit, lsu *loader.SymbolBuilder) {
|
|
|
|
|
type fileDir struct {
|
|
|
|
|
base string
|
|
|
|
|
dir int
|
|
|
|
|
}
|
|
|
|
|
dirNums := make(map[string]int)
|
|
|
|
|
dirs := []string{""}
|
|
|
|
|
files := []fileDir{}
|
|
|
|
|
|
|
|
|
|
// Preprocess files to collect directories. This assumes that the
|
|
|
|
|
// file table is already de-duped.
|
|
|
|
|
for i, name := range unit.FileTable {
|
|
|
|
|
name := expandFile(name)
|
|
|
|
|
if len(name) == 0 {
|
|
|
|
|
// Can't have empty filenames, and having a unique
|
|
|
|
|
// filename is quite useful for debugging.
|
|
|
|
|
name = fmt.Sprintf("<missing>_%d", i)
|
|
|
|
|
}
|
|
|
|
|
// Note the use of "path" here and not "filepath". The compiler
|
|
|
|
|
// hard-codes to use "/" in DWARF paths (even for Windows), so we
|
|
|
|
|
// want to maintain that here.
|
|
|
|
|
file := path.Base(name)
|
|
|
|
|
dir := path.Dir(name)
|
|
|
|
|
dirIdx, ok := dirNums[dir]
|
|
|
|
|
if !ok && dir != "." {
|
|
|
|
|
dirIdx = len(dirNums) + 1
|
|
|
|
|
dirNums[dir] = dirIdx
|
|
|
|
|
dirs = append(dirs, dir)
|
|
|
|
|
}
|
|
|
|
|
files = append(files, fileDir{base: file, dir: dirIdx})
|
|
|
|
|
|
|
|
|
|
// We can't use something that may be dead-code
|
|
|
|
|
// eliminated from a binary here. proc.go contains
|
|
|
|
|
// main and the scheduler, so it's not going anywhere.
|
2021-08-22 17:26:20 +08:00
|
|
|
if i := strings.Index(name, "runtime/proc.go"); i >= 0 && unit.Lib.Pkg == "runtime" {
|
cmd/link: emit include directories in DWARF line table prologue
This patch changes the way the linker emits the DWARF line table
prologue, specifically the file table. Previously files were left
unmodified, and the directory table was empty. For each compilation
unit we now scan the unit file table and build up a common set of
directories, emit them into the directory table, and then emit file
entries that refer to the dirs. This provides a modest binary size
savings.
For kubernetes kubelet:
$ objdump -h /tmp/kubelet.old | fgrep debug_line
36 .zdebug_line 019a55f5 0000000000000000 0000000000000000 084a5123 2**0
$ objdump -h /tmp/kubelet.new | fgrep debug_line
36 .zdebug_line 01146fd2 0000000000000000 0000000000000000 084a510a 2**0
[where the value following the section name above is the section size
in hex, so roughly a 30% decrease in this case.]
The actual savings will depend on the length of the pathnames
involved, so it's hard to really pin down how much savings we'll see
here. In addition, emitting the files this way reduces the
"compressibility" of the line table, so there could even be cases
where we don't win at all.
Updates #6853, #19784, #36495.
Change-Id: I298d8561da5ed3ebc9d38aa772874851baa2f4f4
Reviewed-on: https://go-review.googlesource.com/c/go/+/263017
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Trust: Than McIntosh <thanm@google.com>
2020-10-16 09:22:31 -04:00
|
|
|
d.dwmu.Lock()
|
|
|
|
|
if gdbscript == "" {
|
|
|
|
|
k := strings.Index(name, "runtime/proc.go")
|
|
|
|
|
gdbscript = name[:k] + "runtime/runtime-gdb.py"
|
|
|
|
|
}
|
|
|
|
|
d.dwmu.Unlock()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Emit directory section. This is a series of nul terminated
|
|
|
|
|
// strings, followed by a single zero byte.
|
|
|
|
|
lsDwsym := dwSym(lsu.Sym())
|
|
|
|
|
for k := 1; k < len(dirs); k++ {
|
|
|
|
|
d.AddString(lsDwsym, dirs[k])
|
|
|
|
|
}
|
|
|
|
|
lsu.AddUint8(0) // terminator
|
|
|
|
|
|
|
|
|
|
// Emit file section.
|
|
|
|
|
for k := 0; k < len(files); k++ {
|
|
|
|
|
d.AddString(lsDwsym, files[k].base)
|
|
|
|
|
dwarf.Uleb128put(d, lsDwsym, int64(files[k].dir))
|
|
|
|
|
lsu.AddUint8(0) // mtime
|
|
|
|
|
lsu.AddUint8(0) // length
|
|
|
|
|
}
|
|
|
|
|
lsu.AddUint8(0) // terminator
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// writelines collects up and chains together the symbols needed to
|
2020-06-10 13:14:15 -04:00
|
|
|
// form the DWARF line table for the specified compilation unit,
|
2020-06-12 09:04:28 -04:00
|
|
|
// returning a list of symbols. The returned list will include an
|
cmd/link: emit include directories in DWARF line table prologue
This patch changes the way the linker emits the DWARF line table
prologue, specifically the file table. Previously files were left
unmodified, and the directory table was empty. For each compilation
unit we now scan the unit file table and build up a common set of
directories, emit them into the directory table, and then emit file
entries that refer to the dirs. This provides a modest binary size
savings.
For kubernetes kubelet:
$ objdump -h /tmp/kubelet.old | fgrep debug_line
36 .zdebug_line 019a55f5 0000000000000000 0000000000000000 084a5123 2**0
$ objdump -h /tmp/kubelet.new | fgrep debug_line
36 .zdebug_line 01146fd2 0000000000000000 0000000000000000 084a510a 2**0
[where the value following the section name above is the section size
in hex, so roughly a 30% decrease in this case.]
The actual savings will depend on the length of the pathnames
involved, so it's hard to really pin down how much savings we'll see
here. In addition, emitting the files this way reduces the
"compressibility" of the line table, so there could even be cases
where we don't win at all.
Updates #6853, #19784, #36495.
Change-Id: I298d8561da5ed3ebc9d38aa772874851baa2f4f4
Reviewed-on: https://go-review.googlesource.com/c/go/+/263017
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Trust: Than McIntosh <thanm@google.com>
2020-10-16 09:22:31 -04:00
|
|
|
// initial symbol containing the line table header and prologue (with
|
2020-06-12 09:04:28 -04:00
|
|
|
// file table), then a series of compiler-emitted line table symbols
|
|
|
|
|
// (one per live function), and finally an epilog symbol containing an
|
cmd/link: emit include directories in DWARF line table prologue
This patch changes the way the linker emits the DWARF line table
prologue, specifically the file table. Previously files were left
unmodified, and the directory table was empty. For each compilation
unit we now scan the unit file table and build up a common set of
directories, emit them into the directory table, and then emit file
entries that refer to the dirs. This provides a modest binary size
savings.
For kubernetes kubelet:
$ objdump -h /tmp/kubelet.old | fgrep debug_line
36 .zdebug_line 019a55f5 0000000000000000 0000000000000000 084a5123 2**0
$ objdump -h /tmp/kubelet.new | fgrep debug_line
36 .zdebug_line 01146fd2 0000000000000000 0000000000000000 084a510a 2**0
[where the value following the section name above is the section size
in hex, so roughly a 30% decrease in this case.]
The actual savings will depend on the length of the pathnames
involved, so it's hard to really pin down how much savings we'll see
here. In addition, emitting the files this way reduces the
"compressibility" of the line table, so there could even be cases
where we don't win at all.
Updates #6853, #19784, #36495.
Change-Id: I298d8561da5ed3ebc9d38aa772874851baa2f4f4
Reviewed-on: https://go-review.googlesource.com/c/go/+/263017
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Trust: Than McIntosh <thanm@google.com>
2020-10-16 09:22:31 -04:00
|
|
|
// end-of-sequence operator. The prologue and epilog symbols are passed
|
2020-06-12 09:04:28 -04:00
|
|
|
// in (having been created earlier); here we add content to them.
|
2020-06-22 13:26:15 -04:00
|
|
|
func (d *dwctxt) writelines(unit *sym.CompilationUnit, lineProlog loader.Sym) []loader.Sym {
|
2020-02-14 16:12:51 -05:00
|
|
|
is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles.
|
|
|
|
|
|
|
|
|
|
unitstart := int64(-1)
|
|
|
|
|
headerstart := int64(-1)
|
|
|
|
|
headerend := int64(-1)
|
|
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
syms := make([]loader.Sym, 0, len(unit.Textp)+2)
|
|
|
|
|
syms = append(syms, lineProlog)
|
|
|
|
|
lsu := d.ldr.MakeSymbolUpdater(lineProlog)
|
|
|
|
|
lsDwsym := dwSym(lineProlog)
|
|
|
|
|
newattr(unit.DWInfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, lsDwsym)
|
2020-04-16 08:29:43 -04:00
|
|
|
|
2020-02-14 16:12:51 -05:00
|
|
|
// Write .debug_line Line Number Program Header (sec 6.2.4)
|
|
|
|
|
// Fields marked with (*) must be changed for 64-bit dwarf
|
|
|
|
|
unitLengthOffset := lsu.Size()
|
|
|
|
|
d.createUnitLength(lsu, 0) // unit_length (*), filled in at end
|
|
|
|
|
unitstart = lsu.Size()
|
|
|
|
|
lsu.AddUint16(d.arch, 2) // dwarf version (appendix F) -- version 3 is incompatible w/ XCode 9.0's dsymutil, latest supported on OSX 10.12 as of 2018-05
|
|
|
|
|
headerLengthOffset := lsu.Size()
|
|
|
|
|
d.addDwarfAddrField(lsu, 0) // header_length (*), filled in at end
|
|
|
|
|
headerstart = lsu.Size()
|
|
|
|
|
|
|
|
|
|
// cpos == unitstart + 4 + 2 + 4
|
|
|
|
|
lsu.AddUint8(1) // minimum_instruction_length
|
|
|
|
|
lsu.AddUint8(is_stmt) // default_is_stmt
|
|
|
|
|
lsu.AddUint8(LINE_BASE & 0xFF) // line_base
|
|
|
|
|
lsu.AddUint8(LINE_RANGE) // line_range
|
|
|
|
|
lsu.AddUint8(OPCODE_BASE) // opcode_base
|
|
|
|
|
lsu.AddUint8(0) // standard_opcode_lengths[1]
|
|
|
|
|
lsu.AddUint8(1) // standard_opcode_lengths[2]
|
|
|
|
|
lsu.AddUint8(1) // standard_opcode_lengths[3]
|
|
|
|
|
lsu.AddUint8(1) // standard_opcode_lengths[4]
|
|
|
|
|
lsu.AddUint8(1) // standard_opcode_lengths[5]
|
|
|
|
|
lsu.AddUint8(0) // standard_opcode_lengths[6]
|
|
|
|
|
lsu.AddUint8(0) // standard_opcode_lengths[7]
|
|
|
|
|
lsu.AddUint8(0) // standard_opcode_lengths[8]
|
|
|
|
|
lsu.AddUint8(1) // standard_opcode_lengths[9]
|
|
|
|
|
lsu.AddUint8(0) // standard_opcode_lengths[10]
|
2020-06-12 09:04:28 -04:00
|
|
|
|
cmd/link: emit include directories in DWARF line table prologue
This patch changes the way the linker emits the DWARF line table
prologue, specifically the file table. Previously files were left
unmodified, and the directory table was empty. For each compilation
unit we now scan the unit file table and build up a common set of
directories, emit them into the directory table, and then emit file
entries that refer to the dirs. This provides a modest binary size
savings.
For kubernetes kubelet:
$ objdump -h /tmp/kubelet.old | fgrep debug_line
36 .zdebug_line 019a55f5 0000000000000000 0000000000000000 084a5123 2**0
$ objdump -h /tmp/kubelet.new | fgrep debug_line
36 .zdebug_line 01146fd2 0000000000000000 0000000000000000 084a510a 2**0
[where the value following the section name above is the section size
in hex, so roughly a 30% decrease in this case.]
The actual savings will depend on the length of the pathnames
involved, so it's hard to really pin down how much savings we'll see
here. In addition, emitting the files this way reduces the
"compressibility" of the line table, so there could even be cases
where we don't win at all.
Updates #6853, #19784, #36495.
Change-Id: I298d8561da5ed3ebc9d38aa772874851baa2f4f4
Reviewed-on: https://go-review.googlesource.com/c/go/+/263017
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Trust: Than McIntosh <thanm@google.com>
2020-10-16 09:22:31 -04:00
|
|
|
// Call helper to emit dir and file sections.
|
|
|
|
|
d.writeDirFileTables(unit, lsu)
|
2020-02-14 16:12:51 -05:00
|
|
|
|
cmd/link: emit include directories in DWARF line table prologue
This patch changes the way the linker emits the DWARF line table
prologue, specifically the file table. Previously files were left
unmodified, and the directory table was empty. For each compilation
unit we now scan the unit file table and build up a common set of
directories, emit them into the directory table, and then emit file
entries that refer to the dirs. This provides a modest binary size
savings.
For kubernetes kubelet:
$ objdump -h /tmp/kubelet.old | fgrep debug_line
36 .zdebug_line 019a55f5 0000000000000000 0000000000000000 084a5123 2**0
$ objdump -h /tmp/kubelet.new | fgrep debug_line
36 .zdebug_line 01146fd2 0000000000000000 0000000000000000 084a510a 2**0
[where the value following the section name above is the section size
in hex, so roughly a 30% decrease in this case.]
The actual savings will depend on the length of the pathnames
involved, so it's hard to really pin down how much savings we'll see
here. In addition, emitting the files this way reduces the
"compressibility" of the line table, so there could even be cases
where we don't win at all.
Updates #6853, #19784, #36495.
Change-Id: I298d8561da5ed3ebc9d38aa772874851baa2f4f4
Reviewed-on: https://go-review.googlesource.com/c/go/+/263017
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Trust: Than McIntosh <thanm@google.com>
2020-10-16 09:22:31 -04:00
|
|
|
// capture length at end of file names.
|
2020-02-14 16:12:51 -05:00
|
|
|
headerend = lsu.Size()
|
2020-06-10 13:14:15 -04:00
|
|
|
unitlen := lsu.Size() - unitstart
|
2020-02-14 16:12:51 -05:00
|
|
|
|
|
|
|
|
// Output the state machine for each function remaining.
|
2020-05-15 18:35:05 -04:00
|
|
|
for _, s := range unit.Textp {
|
2020-02-14 16:12:51 -05:00
|
|
|
fnSym := loader.Sym(s)
|
|
|
|
|
_, _, _, lines := d.ldr.GetFuncDwarfAuxSyms(fnSym)
|
2020-06-10 13:14:15 -04:00
|
|
|
|
|
|
|
|
// Chain the line symbol onto the list.
|
2020-02-14 16:12:51 -05:00
|
|
|
if lines != 0 {
|
2020-06-10 13:14:15 -04:00
|
|
|
syms = append(syms, lines)
|
|
|
|
|
unitlen += int64(len(d.ldr.Data(lines)))
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if d.linkctxt.HeadType == objabi.Haix {
|
2020-06-12 09:04:28 -04:00
|
|
|
addDwsectCUSize(".debug_line", unit.Lib.Pkg, uint64(unitlen))
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
2020-06-10 13:14:15 -04:00
|
|
|
|
2020-02-14 16:12:51 -05:00
|
|
|
if isDwarf64(d.linkctxt) {
|
2020-06-10 13:14:15 -04:00
|
|
|
lsu.SetUint(d.arch, unitLengthOffset+4, uint64(unitlen)) // +4 because of 0xFFFFFFFF
|
2020-02-14 16:12:51 -05:00
|
|
|
lsu.SetUint(d.arch, headerLengthOffset, uint64(headerend-headerstart))
|
|
|
|
|
} else {
|
2020-06-10 13:14:15 -04:00
|
|
|
lsu.SetUint32(d.arch, unitLengthOffset, uint32(unitlen))
|
2020-02-14 16:12:51 -05:00
|
|
|
lsu.SetUint32(d.arch, headerLengthOffset, uint32(headerend-headerstart))
|
|
|
|
|
}
|
2020-06-10 13:14:15 -04:00
|
|
|
|
|
|
|
|
return syms
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
// writepcranges generates the DW_AT_ranges table for compilation unit
|
|
|
|
|
// "unit", and returns a collection of ranges symbols (one for the
|
|
|
|
|
// compilation unit DIE itself and the remainder from functions in the unit).
|
|
|
|
|
func (d *dwctxt) writepcranges(unit *sym.CompilationUnit, base loader.Sym, pcs []dwarf.Range, rangeProlog loader.Sym) []loader.Sym {
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
syms := make([]loader.Sym, 0, len(unit.RangeSyms)+1)
|
|
|
|
|
syms = append(syms, rangeProlog)
|
|
|
|
|
rsu := d.ldr.MakeSymbolUpdater(rangeProlog)
|
|
|
|
|
rDwSym := dwSym(rangeProlog)
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
// Create PC ranges for the compilation unit DIE.
|
2020-02-14 16:12:51 -05:00
|
|
|
newattr(unit.DWInfo, dwarf.DW_AT_ranges, dwarf.DW_CLS_PTR, rsu.Size(), rDwSym)
|
|
|
|
|
newattr(unit.DWInfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, 0, dwSym(base))
|
|
|
|
|
dwarf.PutBasedRanges(d, rDwSym, pcs)
|
|
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
// Collect up the ranges for functions in the unit.
|
|
|
|
|
rsize := uint64(rsu.Size())
|
|
|
|
|
for _, ls := range unit.RangeSyms {
|
|
|
|
|
s := loader.Sym(ls)
|
|
|
|
|
syms = append(syms, s)
|
|
|
|
|
rsize += uint64(d.ldr.SymSize(s))
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 16:12:51 -05:00
|
|
|
if d.linkctxt.HeadType == objabi.Haix {
|
2020-06-12 09:04:28 -04:00
|
|
|
addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, rsize)
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
2020-06-12 09:04:28 -04:00
|
|
|
|
|
|
|
|
return syms
|
2017-10-10 16:19:49 -04:00
|
|
|
}
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
/*
|
|
|
|
|
* Emit .debug_frame
|
|
|
|
|
*/
|
|
|
|
|
const (
|
2016-04-13 13:34:41 -04:00
|
|
|
dataAlignmentFactor = -4
|
2015-02-27 22:57:28 -05:00
|
|
|
)
|
|
|
|
|
|
2016-02-29 13:07:50 -09:00
|
|
|
// appendPCDeltaCFA appends per-PC CFA deltas to b and returns the final slice.
|
2017-10-01 02:37:20 +00:00
|
|
|
func appendPCDeltaCFA(arch *sys.Arch, b []byte, deltapc, cfa int64) []byte {
|
2016-07-28 13:04:41 -04:00
|
|
|
b = append(b, dwarf.DW_CFA_def_cfa_offset_sf)
|
|
|
|
|
b = dwarf.AppendSleb128(b, cfa/dataAlignmentFactor)
|
2016-02-29 13:07:50 -09:00
|
|
|
|
|
|
|
|
switch {
|
|
|
|
|
case deltapc < 0x40:
|
2016-07-28 13:04:41 -04:00
|
|
|
b = append(b, uint8(dwarf.DW_CFA_advance_loc+deltapc))
|
2016-02-29 13:07:50 -09:00
|
|
|
case deltapc < 0x100:
|
2016-07-28 13:04:41 -04:00
|
|
|
b = append(b, dwarf.DW_CFA_advance_loc1)
|
2016-02-29 13:07:50 -09:00
|
|
|
b = append(b, uint8(deltapc))
|
|
|
|
|
case deltapc < 0x10000:
|
2017-10-01 02:37:20 +00:00
|
|
|
b = append(b, dwarf.DW_CFA_advance_loc2, 0, 0)
|
|
|
|
|
arch.ByteOrder.PutUint16(b[len(b)-2:], uint16(deltapc))
|
2016-02-29 13:07:50 -09:00
|
|
|
default:
|
2017-10-01 02:37:20 +00:00
|
|
|
b = append(b, dwarf.DW_CFA_advance_loc4, 0, 0, 0, 0)
|
|
|
|
|
arch.ByteOrder.PutUint32(b[len(b)-4:], uint32(deltapc))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2016-02-29 13:07:50 -09:00
|
|
|
return b
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2020-06-11 14:48:08 -04:00
|
|
|
func (d *dwctxt) writeframes(fs loader.Sym) dwarfSecInfo {
|
2020-02-14 16:12:51 -05:00
|
|
|
fsd := dwSym(fs)
|
|
|
|
|
fsu := d.ldr.MakeSymbolUpdater(fs)
|
|
|
|
|
fsu.SetType(sym.SDWARFSECT)
|
|
|
|
|
isdw64 := isDwarf64(d.linkctxt)
|
2022-04-18 13:39:52 -04:00
|
|
|
haslr := d.linkctxt.Arch.HasLR
|
2020-02-14 16:12:51 -05:00
|
|
|
|
|
|
|
|
// Length field is 4 bytes on Dwarf32 and 12 bytes on Dwarf64
|
|
|
|
|
lengthFieldSize := int64(4)
|
|
|
|
|
if isdw64 {
|
|
|
|
|
lengthFieldSize += 8
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Emit the CIE, Section 6.4.1
|
|
|
|
|
cieReserve := uint32(16)
|
|
|
|
|
if haslr {
|
|
|
|
|
cieReserve = 32
|
|
|
|
|
}
|
|
|
|
|
if isdw64 {
|
|
|
|
|
cieReserve += 4 // 4 bytes added for cid
|
|
|
|
|
}
|
|
|
|
|
d.createUnitLength(fsu, uint64(cieReserve)) // initial length, must be multiple of thearch.ptrsize
|
|
|
|
|
d.addDwarfAddrField(fsu, ^uint64(0)) // cid
|
|
|
|
|
fsu.AddUint8(3) // dwarf version (appendix F)
|
|
|
|
|
fsu.AddUint8(0) // augmentation ""
|
|
|
|
|
dwarf.Uleb128put(d, fsd, 1) // code_alignment_factor
|
|
|
|
|
dwarf.Sleb128put(d, fsd, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor
|
|
|
|
|
dwarf.Uleb128put(d, fsd, int64(thearch.Dwarfreglr)) // return_address_register
|
|
|
|
|
|
|
|
|
|
fsu.AddUint8(dwarf.DW_CFA_def_cfa) // Set the current frame address..
|
|
|
|
|
dwarf.Uleb128put(d, fsd, int64(thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)...
|
|
|
|
|
if haslr {
|
|
|
|
|
dwarf.Uleb128put(d, fsd, int64(0)) // ...plus a 0 offset.
|
|
|
|
|
|
|
|
|
|
fsu.AddUint8(dwarf.DW_CFA_same_value) // The platform's link register is unchanged during the prologue.
|
|
|
|
|
dwarf.Uleb128put(d, fsd, int64(thearch.Dwarfreglr))
|
|
|
|
|
|
|
|
|
|
fsu.AddUint8(dwarf.DW_CFA_val_offset) // The previous value...
|
|
|
|
|
dwarf.Uleb128put(d, fsd, int64(thearch.Dwarfregsp)) // ...of the platform's SP register...
|
|
|
|
|
dwarf.Uleb128put(d, fsd, int64(0)) // ...is CFA+0.
|
|
|
|
|
} else {
|
|
|
|
|
dwarf.Uleb128put(d, fsd, int64(d.arch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame).
|
|
|
|
|
|
|
|
|
|
fsu.AddUint8(dwarf.DW_CFA_offset_extended) // The previous value...
|
|
|
|
|
dwarf.Uleb128put(d, fsd, int64(thearch.Dwarfreglr)) // ...of the return address...
|
|
|
|
|
dwarf.Uleb128put(d, fsd, int64(-d.arch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)].
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pad := int64(cieReserve) + lengthFieldSize - int64(len(d.ldr.Data(fs)))
|
|
|
|
|
|
|
|
|
|
if pad < 0 {
|
|
|
|
|
Exitf("dwarf: cieReserve too small by %d bytes.", -pad)
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-16 08:29:43 -04:00
|
|
|
internalExec := d.linkctxt.BuildMode == BuildModeExe && d.linkctxt.IsInternal()
|
|
|
|
|
addAddrPlus := loader.GenAddAddrPlusFunc(internalExec)
|
|
|
|
|
|
2020-02-14 16:12:51 -05:00
|
|
|
fsu.AddBytes(zeros[:pad])
|
|
|
|
|
|
|
|
|
|
var deltaBuf []byte
|
|
|
|
|
pcsp := obj.NewPCIter(uint32(d.arch.MinLC))
|
2020-05-15 18:35:05 -04:00
|
|
|
for _, s := range d.linkctxt.Textp {
|
2020-02-14 16:12:51 -05:00
|
|
|
fn := loader.Sym(s)
|
|
|
|
|
fi := d.ldr.FuncInfo(fn)
|
|
|
|
|
if !fi.Valid() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-09-28 16:20:29 -04:00
|
|
|
fpcsp := d.ldr.Pcsp(s)
|
2020-02-14 16:12:51 -05:00
|
|
|
|
|
|
|
|
// Emit a FDE, Section 6.4.1.
|
|
|
|
|
// First build the section contents into a byte buffer.
|
|
|
|
|
deltaBuf = deltaBuf[:0]
|
cmd/asm, cmd/link, runtime: introduce FuncInfo flag bits
The runtime traceback code has its own definition of which functions
mark the top frame of a stack, separate from the TOPFRAME bits that
exist in the assembly and are passed along in DWARF information.
It's error-prone and redundant to have two different sources of truth.
This CL provides the actual TOPFRAME bits to the runtime, so that
the runtime can use those bits instead of reinventing its own category.
This CL also adds a new bit, SPWRITE, which marks functions that
write directly to SP (anything but adding and subtracting constants).
Such functions must stop a traceback, because the traceback has no
way to rederive the SP on entry. Again, the runtime has its own definition
which is mostly correct, but also missing some functions. During ordinary
goroutine context switches, such functions do not appear on the stack,
so the incompleteness in the runtime usually doesn't matter.
But profiling signals can arrive at any moment, and the runtime may
crash during traceback if it attempts to unwind an SP-writing frame
and gets out-of-sync with the actual stack. The runtime contains code
to try to detect likely candidates but again it is incomplete.
Deriving the SPWRITE bit automatically from the actual assembly code
provides the complete truth, and passing it to the runtime lets the
runtime use it.
This CL is part of a stack adding windows/arm64
support (#36439), intended to land in the Go 1.17 cycle.
This CL is, however, not windows/arm64-specific.
It is cleanup meant to make the port (and future ports) easier.
Change-Id: I227f53b23ac5b3dabfcc5e8ee3f00df4e113cf58
Reviewed-on: https://go-review.googlesource.com/c/go/+/288800
Trust: Russ Cox <rsc@golang.org>
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-01-28 15:21:33 -05:00
|
|
|
if haslr && fi.TopFrame() {
|
2020-02-14 16:12:51 -05:00
|
|
|
// Mark the link register as having an undefined value.
|
|
|
|
|
// This stops call stack unwinders progressing any further.
|
|
|
|
|
// TODO: similar mark on non-LR architectures.
|
|
|
|
|
deltaBuf = append(deltaBuf, dwarf.DW_CFA_undefined)
|
|
|
|
|
deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr))
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-07 11:31:20 -04:00
|
|
|
for pcsp.Init(d.linkctxt.loader.Data(fpcsp)); !pcsp.Done; pcsp.Next() {
|
2020-02-14 16:12:51 -05:00
|
|
|
nextpc := pcsp.NextPC
|
|
|
|
|
|
|
|
|
|
// pciterinit goes up to the end of the function,
|
|
|
|
|
// but DWARF expects us to stop just before the end.
|
|
|
|
|
if int64(nextpc) == int64(len(d.ldr.Data(fn))) {
|
|
|
|
|
nextpc--
|
|
|
|
|
if nextpc < pcsp.PC {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
spdelta := int64(pcsp.Value)
|
|
|
|
|
if !haslr {
|
|
|
|
|
// Return address has been pushed onto stack.
|
|
|
|
|
spdelta += int64(d.arch.PtrSize)
|
|
|
|
|
}
|
|
|
|
|
|
cmd/asm, cmd/link, runtime: introduce FuncInfo flag bits
The runtime traceback code has its own definition of which functions
mark the top frame of a stack, separate from the TOPFRAME bits that
exist in the assembly and are passed along in DWARF information.
It's error-prone and redundant to have two different sources of truth.
This CL provides the actual TOPFRAME bits to the runtime, so that
the runtime can use those bits instead of reinventing its own category.
This CL also adds a new bit, SPWRITE, which marks functions that
write directly to SP (anything but adding and subtracting constants).
Such functions must stop a traceback, because the traceback has no
way to rederive the SP on entry. Again, the runtime has its own definition
which is mostly correct, but also missing some functions. During ordinary
goroutine context switches, such functions do not appear on the stack,
so the incompleteness in the runtime usually doesn't matter.
But profiling signals can arrive at any moment, and the runtime may
crash during traceback if it attempts to unwind an SP-writing frame
and gets out-of-sync with the actual stack. The runtime contains code
to try to detect likely candidates but again it is incomplete.
Deriving the SPWRITE bit automatically from the actual assembly code
provides the complete truth, and passing it to the runtime lets the
runtime use it.
This CL is part of a stack adding windows/arm64
support (#36439), intended to land in the Go 1.17 cycle.
This CL is, however, not windows/arm64-specific.
It is cleanup meant to make the port (and future ports) easier.
Change-Id: I227f53b23ac5b3dabfcc5e8ee3f00df4e113cf58
Reviewed-on: https://go-review.googlesource.com/c/go/+/288800
Trust: Russ Cox <rsc@golang.org>
Trust: Jason A. Donenfeld <Jason@zx2c4.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com>
2021-01-28 15:21:33 -05:00
|
|
|
if haslr && !fi.TopFrame() {
|
2020-02-14 16:12:51 -05:00
|
|
|
// TODO(bryanpkc): This is imprecise. In general, the instruction
|
|
|
|
|
// that stores the return address to the stack frame is not the
|
|
|
|
|
// same one that allocates the frame.
|
|
|
|
|
if pcsp.Value > 0 {
|
|
|
|
|
// The return address is preserved at (CFA-frame_size)
|
|
|
|
|
// after a stack frame has been allocated.
|
|
|
|
|
deltaBuf = append(deltaBuf, dwarf.DW_CFA_offset_extended_sf)
|
|
|
|
|
deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr))
|
|
|
|
|
deltaBuf = dwarf.AppendSleb128(deltaBuf, -spdelta/dataAlignmentFactor)
|
|
|
|
|
} else {
|
|
|
|
|
// The return address is restored into the link register
|
|
|
|
|
// when a stack frame has been de-allocated.
|
|
|
|
|
deltaBuf = append(deltaBuf, dwarf.DW_CFA_same_value)
|
|
|
|
|
deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(thearch.Dwarfreglr))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deltaBuf = appendPCDeltaCFA(d.arch, deltaBuf, int64(nextpc)-int64(pcsp.PC), spdelta)
|
|
|
|
|
}
|
|
|
|
|
pad := int(Rnd(int64(len(deltaBuf)), int64(d.arch.PtrSize))) - len(deltaBuf)
|
|
|
|
|
deltaBuf = append(deltaBuf, zeros[:pad]...)
|
|
|
|
|
|
|
|
|
|
// Emit the FDE header, Section 6.4.1.
|
|
|
|
|
// 4 bytes: length, must be multiple of thearch.ptrsize
|
|
|
|
|
// 4/8 bytes: Pointer to the CIE above, at offset 0
|
|
|
|
|
// ptrsize: initial location
|
|
|
|
|
// ptrsize: address range
|
|
|
|
|
|
|
|
|
|
fdeLength := uint64(4 + 2*d.arch.PtrSize + len(deltaBuf))
|
|
|
|
|
if isdw64 {
|
|
|
|
|
fdeLength += 4 // 4 bytes added for CIE pointer
|
|
|
|
|
}
|
|
|
|
|
d.createUnitLength(fsu, fdeLength)
|
|
|
|
|
|
|
|
|
|
if d.linkctxt.LinkMode == LinkExternal {
|
|
|
|
|
d.addDwarfAddrRef(fsu, fs)
|
|
|
|
|
} else {
|
|
|
|
|
d.addDwarfAddrField(fsu, 0) // CIE offset
|
|
|
|
|
}
|
2020-04-16 08:29:43 -04:00
|
|
|
addAddrPlus(fsu, d.arch, s, 0)
|
2020-02-14 16:12:51 -05:00
|
|
|
fsu.AddUintXX(d.arch, uint64(len(d.ldr.Data(fn))), d.arch.PtrSize) // address range
|
|
|
|
|
fsu.AddBytes(deltaBuf)
|
|
|
|
|
|
|
|
|
|
if d.linkctxt.HeadType == objabi.Haix {
|
2020-04-06 20:56:34 -04:00
|
|
|
addDwsectCUSize(".debug_frame", d.ldr.SymPkg(fn), fdeLength+uint64(lengthFieldSize))
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-17 09:11:57 -04:00
|
|
|
return dwarfSecInfo{syms: []loader.Sym{fs}}
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Walk DWarfDebugInfoEntries, and emit .debug_info
|
|
|
|
|
*/
|
2019-11-20 10:43:11 -05:00
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
const (
|
|
|
|
|
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
|
|
|
|
|
)
|
|
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
func (d *dwctxt) writeUnitInfo(u *sym.CompilationUnit, abbrevsym loader.Sym, infoEpilog loader.Sym) []loader.Sym {
|
2020-06-11 14:48:08 -04:00
|
|
|
syms := []loader.Sym{}
|
2021-01-07 16:25:41 -05:00
|
|
|
if len(u.Textp) == 0 && u.DWInfo.Child == nil && len(u.VarDIEs) == 0 {
|
2020-06-11 14:48:08 -04:00
|
|
|
return syms
|
|
|
|
|
}
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-11 14:48:08 -04:00
|
|
|
compunit := u.DWInfo
|
|
|
|
|
s := d.dtolsym(compunit.Sym)
|
|
|
|
|
su := d.ldr.MakeSymbolUpdater(s)
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-11 14:48:08 -04:00
|
|
|
// Write .debug_info Compilation Unit Header (sec 7.5.1)
|
|
|
|
|
// Fields marked with (*) must be changed for 64-bit dwarf
|
|
|
|
|
// This must match COMPUNITHEADERSIZE above.
|
|
|
|
|
d.createUnitLength(su, 0) // unit_length (*), will be filled in later.
|
|
|
|
|
su.AddUint16(d.arch, 4) // dwarf version (appendix F)
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-11 14:48:08 -04:00
|
|
|
// debug_abbrev_offset (*)
|
|
|
|
|
d.addDwarfAddrRef(su, abbrevsym)
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-11 14:48:08 -04:00
|
|
|
su.AddUint8(uint8(d.arch.PtrSize)) // address_size
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-11 14:48:08 -04:00
|
|
|
ds := dwSym(s)
|
|
|
|
|
dwarf.Uleb128put(d, ds, int64(compunit.Abbrev))
|
|
|
|
|
dwarf.PutAttrs(d, ds, compunit.Abbrev, compunit.Attr)
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
// This is an under-estimate; more will be needed for type DIEs.
|
|
|
|
|
cu := make([]loader.Sym, 0, len(u.AbsFnDIEs)+len(u.FuncDIEs))
|
|
|
|
|
cu = append(cu, s)
|
2023-09-01 13:12:49 -07:00
|
|
|
cu = append(cu, u.AbsFnDIEs...)
|
|
|
|
|
cu = append(cu, u.FuncDIEs...)
|
2020-06-11 14:48:08 -04:00
|
|
|
if u.Consts != 0 {
|
|
|
|
|
cu = append(cu, loader.Sym(u.Consts))
|
|
|
|
|
}
|
2023-09-01 13:12:49 -07:00
|
|
|
cu = append(cu, u.VarDIEs...)
|
2020-06-11 14:48:08 -04:00
|
|
|
var cusize int64
|
|
|
|
|
for _, child := range cu {
|
|
|
|
|
cusize += int64(len(d.ldr.Data(child)))
|
|
|
|
|
}
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-11 14:48:08 -04:00
|
|
|
for die := compunit.Child; die != nil; die = die.Link {
|
|
|
|
|
l := len(cu)
|
|
|
|
|
lastSymSz := int64(len(d.ldr.Data(cu[l-1])))
|
|
|
|
|
cu = d.putdie(cu, die)
|
|
|
|
|
if lastSymSz != int64(len(d.ldr.Data(cu[l-1]))) {
|
|
|
|
|
// putdie will sometimes append directly to the last symbol of the list
|
|
|
|
|
cusize = cusize - lastSymSz + int64(len(d.ldr.Data(cu[l-1])))
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
2020-06-11 14:48:08 -04:00
|
|
|
for _, child := range cu[l:] {
|
2020-02-14 16:12:51 -05:00
|
|
|
cusize += int64(len(d.ldr.Data(child)))
|
|
|
|
|
}
|
2020-06-11 14:48:08 -04:00
|
|
|
}
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
culu := d.ldr.MakeSymbolUpdater(infoEpilog)
|
2020-06-11 14:48:08 -04:00
|
|
|
culu.AddUint8(0) // closes compilation unit DIE
|
2020-06-12 09:04:28 -04:00
|
|
|
cu = append(cu, infoEpilog)
|
2020-06-11 14:48:08 -04:00
|
|
|
cusize++
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-06-11 14:48:08 -04:00
|
|
|
// Save size for AIX symbol table.
|
|
|
|
|
if d.linkctxt.HeadType == objabi.Haix {
|
2020-06-12 09:04:28 -04:00
|
|
|
addDwsectCUSize(".debug_info", d.getPkgFromCUSym(s), uint64(cusize))
|
2020-06-11 14:48:08 -04:00
|
|
|
}
|
|
|
|
|
if isDwarf64(d.linkctxt) {
|
|
|
|
|
cusize -= 12 // exclude the length field.
|
|
|
|
|
su.SetUint(d.arch, 4, uint64(cusize)) // 4 because of 0XFFFFFFFF
|
|
|
|
|
} else {
|
|
|
|
|
cusize -= 4 // exclude the length field.
|
|
|
|
|
su.SetUint32(d.arch, 0, uint32(cusize))
|
|
|
|
|
}
|
|
|
|
|
return append(syms, cu...)
|
|
|
|
|
}
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) writegdbscript() dwarfSecInfo {
|
2020-02-14 16:12:51 -05:00
|
|
|
// TODO (aix): make it available
|
|
|
|
|
if d.linkctxt.HeadType == objabi.Haix {
|
2020-04-17 09:11:57 -04:00
|
|
|
return dwarfSecInfo{}
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
|
|
|
|
if d.linkctxt.LinkMode == LinkExternal && d.linkctxt.HeadType == objabi.Hwindows && d.linkctxt.BuildMode == BuildModeCArchive {
|
|
|
|
|
// gcc on Windows places .debug_gdb_scripts in the wrong location, which
|
|
|
|
|
// causes the program not to run. See https://golang.org/issue/20183
|
|
|
|
|
// Non c-archives can avoid this issue via a linker script
|
|
|
|
|
// (see fix near writeGDBLinkerScript).
|
|
|
|
|
// c-archive users would need to specify the linker script manually.
|
|
|
|
|
// For UX it's better not to deal with this.
|
2020-04-17 09:11:57 -04:00
|
|
|
return dwarfSecInfo{}
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
2020-04-17 09:11:57 -04:00
|
|
|
if gdbscript == "" {
|
|
|
|
|
return dwarfSecInfo{}
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
|
|
|
|
|
2020-06-12 09:35:42 -04:00
|
|
|
gs := d.ldr.CreateSymForUpdate(".debug_gdb_scripts", 0)
|
|
|
|
|
gs.SetType(sym.SDWARFSECT)
|
2020-02-14 16:12:51 -05:00
|
|
|
|
2021-08-23 08:40:32 +00:00
|
|
|
gs.AddUint8(GdbScriptPythonFileId)
|
2020-06-12 09:35:42 -04:00
|
|
|
gs.Addstring(gdbscript)
|
|
|
|
|
return dwarfSecInfo{syms: []loader.Sym{gs.Sym()}}
|
2019-03-05 09:58:58 +01:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// FIXME: might be worth looking replacing this map with a function
|
|
|
|
|
// that switches based on symbol instead.
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
var prototypedies map[string]*dwarf.DWDie
|
2015-04-08 12:55:34 -07:00
|
|
|
|
2018-04-24 13:05:10 +02:00
|
|
|
func dwarfEnabled(ctxt *Link) bool {
|
2016-08-21 18:34:24 -04:00
|
|
|
if *FlagW { // disable dwarf
|
2018-04-24 13:05:10 +02:00
|
|
|
return false
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2023-03-24 23:07:58 -07:00
|
|
|
if ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hjs || ctxt.HeadType == objabi.Hwasip1 {
|
2018-04-24 13:05:10 +02:00
|
|
|
return false
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2017-10-05 10:20:17 -04:00
|
|
|
if ctxt.LinkMode == LinkExternal {
|
2017-02-08 12:47:43 +11:00
|
|
|
switch {
|
2017-10-07 13:43:38 -04:00
|
|
|
case ctxt.IsELF:
|
2017-10-07 13:49:44 -04:00
|
|
|
case ctxt.HeadType == objabi.Hdarwin:
|
|
|
|
|
case ctxt.HeadType == objabi.Hwindows:
|
2019-02-20 16:29:00 +01:00
|
|
|
case ctxt.HeadType == objabi.Haix:
|
2019-02-20 16:39:09 +01:00
|
|
|
res, err := dwarf.IsDWARFEnabledOnAIXLd(ctxt.extld())
|
|
|
|
|
if err != nil {
|
|
|
|
|
Exitf("%v", err)
|
|
|
|
|
}
|
|
|
|
|
return res
|
2017-02-08 12:47:43 +11:00
|
|
|
default:
|
2018-04-24 13:05:10 +02:00
|
|
|
return false
|
2015-04-08 12:55:34 -07:00
|
|
|
}
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
2015-04-08 12:55:34 -07:00
|
|
|
|
2018-04-24 13:05:10 +02:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// mkBuiltinType populates the dwctxt2 sym lookup maps for the
|
|
|
|
|
// newly created builtin type DIE 'typeDie'.
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) mkBuiltinType(ctxt *Link, abrv int, tname string) *dwarf.DWDie {
|
2019-11-20 10:43:11 -05:00
|
|
|
// create type DIE
|
2021-07-01 09:27:46 -04:00
|
|
|
die := d.newdie(&dwtypes, abrv, tname)
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
// Look up type symbol.
|
2021-05-08 00:45:06 +07:00
|
|
|
gotype := d.lookupOrDiag("type:" + tname)
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
// Map from die sym to type sym
|
2020-02-19 16:16:17 -05:00
|
|
|
ds := loader.Sym(die.Sym.(dwSym))
|
|
|
|
|
d.rtmap[ds] = gotype
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
// Map from type to def sym
|
2020-02-19 16:16:17 -05:00
|
|
|
d.tdmap[gotype] = ds
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
return die
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-20 15:06:22 -04:00
|
|
|
// dwarfVisitFunction takes a function (text) symbol and processes the
|
|
|
|
|
// subprogram DIE for the function and picks up any other DIEs
|
|
|
|
|
// (absfns, types) that it references.
|
|
|
|
|
func (d *dwctxt) dwarfVisitFunction(fnSym loader.Sym, unit *sym.CompilationUnit) {
|
|
|
|
|
// The DWARF subprogram DIE symbol is listed as an aux sym
|
|
|
|
|
// of the text (fcn) symbol, so ask the loader to retrieve it,
|
|
|
|
|
// as well as the associated range symbol.
|
|
|
|
|
infosym, _, rangesym, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
|
|
|
|
|
if infosym == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(infosym, true)
|
|
|
|
|
d.ldr.SetAttrReachable(infosym, true)
|
|
|
|
|
unit.FuncDIEs = append(unit.FuncDIEs, sym.LoaderSym(infosym))
|
|
|
|
|
if rangesym != 0 {
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(rangesym, true)
|
|
|
|
|
d.ldr.SetAttrReachable(rangesym, true)
|
|
|
|
|
unit.RangeSyms = append(unit.RangeSyms, sym.LoaderSym(rangesym))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Walk the relocations of the subprogram DIE symbol to discover
|
|
|
|
|
// references to abstract function DIEs, Go type DIES, and
|
|
|
|
|
// (via R_USETYPE relocs) types that were originally assigned to
|
|
|
|
|
// locals/params but were optimized away.
|
|
|
|
|
drelocs := d.ldr.Relocs(infosym)
|
|
|
|
|
for ri := 0; ri < drelocs.Count(); ri++ {
|
2020-07-29 13:26:50 -04:00
|
|
|
r := drelocs.At(ri)
|
2020-05-20 15:06:22 -04:00
|
|
|
// Look for "use type" relocs.
|
|
|
|
|
if r.Type() == objabi.R_USETYPE {
|
|
|
|
|
d.defgotype(r.Sym())
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if r.Type() != objabi.R_DWARFSECREF {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsym := r.Sym()
|
|
|
|
|
rst := d.ldr.SymType(rsym)
|
|
|
|
|
|
|
|
|
|
// Look for abstract function references.
|
|
|
|
|
if rst == sym.SDWARFABSFCN {
|
|
|
|
|
if !d.ldr.AttrOnList(rsym) {
|
|
|
|
|
// abstract function
|
|
|
|
|
d.ldr.SetAttrOnList(rsym, true)
|
|
|
|
|
unit.AbsFnDIEs = append(unit.AbsFnDIEs, sym.LoaderSym(rsym))
|
|
|
|
|
d.importInfoSymbol(rsym)
|
|
|
|
|
}
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Look for type references.
|
|
|
|
|
if rst != sym.SDWARFTYPE && rst != sym.Sxxx {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if _, ok := d.rtmap[rsym]; ok {
|
|
|
|
|
// type already generated
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rsn := d.ldr.SymName(rsym)
|
|
|
|
|
tn := rsn[len(dwarf.InfoPrefix):]
|
2021-05-08 00:45:06 +07:00
|
|
|
ts := d.ldr.Lookup("type:"+tn, 0)
|
2020-05-20 15:06:22 -04:00
|
|
|
d.defgotype(ts)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-24 13:05:10 +02:00
|
|
|
// dwarfGenerateDebugInfo generated debug info entries for all types,
|
|
|
|
|
// variables and functions in the program.
|
|
|
|
|
// Along with dwarfGenerateDebugSyms they are the two main entry points into
|
|
|
|
|
// dwarf generation: dwarfGenerateDebugInfo does all the work that should be
|
2019-11-20 10:43:11 -05:00
|
|
|
// done before symbol names are mangled while dwarfGenerateDebugSyms does
|
2018-04-24 13:05:10 +02:00
|
|
|
// all the work that can only be done after addresses have been assigned to
|
|
|
|
|
// text symbols.
|
2020-02-21 11:00:13 -05:00
|
|
|
func dwarfGenerateDebugInfo(ctxt *Link) {
|
2018-04-24 13:05:10 +02:00
|
|
|
if !dwarfEnabled(ctxt) {
|
|
|
|
|
return
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-01 09:27:46 -04:00
|
|
|
d := &dwctxt{
|
|
|
|
|
linkctxt: ctxt,
|
|
|
|
|
ldr: ctxt.loader,
|
|
|
|
|
arch: ctxt.Arch,
|
|
|
|
|
tmap: make(map[string]loader.Sym),
|
|
|
|
|
tdmap: make(map[loader.Sym]loader.Sym),
|
|
|
|
|
rtmap: make(map[loader.Sym]loader.Sym),
|
|
|
|
|
}
|
2021-05-08 00:45:06 +07:00
|
|
|
d.typeRuntimeEface = d.lookupOrDiag("type:runtime.eface")
|
|
|
|
|
d.typeRuntimeIface = d.lookupOrDiag("type:runtime.iface")
|
2019-11-20 10:43:11 -05:00
|
|
|
|
2019-02-20 16:29:00 +01:00
|
|
|
if ctxt.HeadType == objabi.Haix {
|
|
|
|
|
// Initial map used to store package size for each DWARF section.
|
|
|
|
|
dwsectCUSize = make(map[string]uint64)
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// For ctxt.Diagnostic messages.
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// Unspecified type. There are no references to this in the symbol table.
|
2021-07-01 09:27:46 -04:00
|
|
|
d.newdie(&dwtypes, dwarf.DW_ABRV_NULLTYPE, "<unspecified>")
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// Some types that must exist to define other ones (uintptr in particular
|
|
|
|
|
// is needed for array size)
|
2024-01-24 18:10:47 +01:00
|
|
|
unsafeptrDie := d.mkBuiltinType(ctxt, dwarf.DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer")
|
|
|
|
|
newattr(unsafeptrDie, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_GO_TYPEREF, 0, dwSym(d.lookupOrDiag("type:unsafe.Pointer")))
|
|
|
|
|
uintptrDie := d.mkBuiltinType(ctxt, dwarf.DW_ABRV_BASETYPE, "uintptr")
|
|
|
|
|
newattr(uintptrDie, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_unsigned, 0)
|
|
|
|
|
newattr(uintptrDie, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(d.arch.PtrSize), 0)
|
2024-04-02 13:08:24 +00:00
|
|
|
newattr(uintptrDie, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, int64(abi.Uintptr), 0)
|
2024-01-24 18:10:47 +01:00
|
|
|
newattr(uintptrDie, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_GO_TYPEREF, 0, dwSym(d.lookupOrDiag("type:uintptr")))
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
d.uintptrInfoSym = d.mustFind("uintptr")
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2016-03-14 09:23:04 -07:00
|
|
|
// Prototypes needed for type synthesis.
|
2016-07-28 13:04:41 -04:00
|
|
|
prototypedies = map[string]*dwarf.DWDie{
|
2021-05-08 00:45:06 +07:00
|
|
|
"type:runtime.stringStructDWARF": nil,
|
|
|
|
|
"type:runtime.slice": nil,
|
|
|
|
|
"type:runtime.sudog": nil,
|
|
|
|
|
"type:runtime.waitq": nil,
|
|
|
|
|
"type:runtime.hchan": nil,
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
2024-05-03 13:03:04 -04:00
|
|
|
if buildcfg.Experiment.SwissMap {
|
|
|
|
|
prototypedies["type:internal/runtime/maps.table"] = nil
|
|
|
|
|
} else {
|
|
|
|
|
prototypedies["type:runtime.hmap"] = nil
|
|
|
|
|
prototypedies["type:runtime.bmap"] = nil
|
|
|
|
|
}
|
2016-03-14 09:23:04 -07:00
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
// Needed by the prettyprinter code for interface inspection.
|
2017-03-18 15:09:40 +01:00
|
|
|
for _, typ := range []string{
|
2023-04-24 15:45:33 -04:00
|
|
|
"type:internal/abi.Type",
|
2023-02-07 17:43:34 -05:00
|
|
|
"type:internal/abi.ArrayType",
|
2023-04-14 18:18:01 -04:00
|
|
|
"type:internal/abi.ChanType",
|
2023-04-25 19:14:05 -04:00
|
|
|
"type:internal/abi.FuncType",
|
|
|
|
|
"type:internal/abi.PtrType",
|
|
|
|
|
"type:internal/abi.SliceType",
|
|
|
|
|
"type:internal/abi.StructType",
|
|
|
|
|
"type:internal/abi.InterfaceType",
|
2023-12-12 20:40:33 -08:00
|
|
|
"type:internal/abi.ITab",
|
2023-01-23 17:34:18 -05:00
|
|
|
"type:internal/abi.Imethod"} {
|
2019-11-20 10:43:11 -05:00
|
|
|
d.defgotype(d.lookupOrDiag(typ))
|
2017-03-18 15:09:40 +01:00
|
|
|
}
|
2024-04-19 13:52:31 -04:00
|
|
|
if buildcfg.Experiment.SwissMap {
|
|
|
|
|
d.defgotype(d.lookupOrDiag("type:internal/abi.SwissMapType"))
|
|
|
|
|
} else {
|
|
|
|
|
d.defgotype(d.lookupOrDiag("type:internal/abi.OldMapType"))
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2018-09-25 11:52:24 +02:00
|
|
|
// fake root DIE for compile unit DIEs
|
|
|
|
|
var dwroot dwarf.DWDie
|
2019-03-26 12:02:36 -04:00
|
|
|
flagVariants := make(map[string]bool)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2018-04-24 13:05:10 +02:00
|
|
|
for _, lib := range ctxt.Library {
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
consts := d.ldr.Lookup(dwarf.ConstInfoPrefix+lib.Pkg, 0)
|
2019-08-09 11:36:03 -04:00
|
|
|
for _, unit := range lib.Units {
|
|
|
|
|
// We drop the constants into the first CU.
|
2019-11-20 10:43:11 -05:00
|
|
|
if consts != 0 {
|
2020-05-15 18:35:05 -04:00
|
|
|
unit.Consts = sym.LoaderSym(consts)
|
2020-05-20 15:06:22 -04:00
|
|
|
d.importInfoSymbol(consts)
|
2019-11-20 10:43:11 -05:00
|
|
|
consts = 0
|
2019-08-09 11:36:03 -04:00
|
|
|
}
|
|
|
|
|
ctxt.compUnits = append(ctxt.compUnits, unit)
|
2018-09-25 11:52:24 +02:00
|
|
|
|
2019-08-09 11:36:03 -04:00
|
|
|
// We need at least one runtime unit.
|
|
|
|
|
if unit.Lib.Pkg == "runtime" {
|
|
|
|
|
ctxt.runtimeCU = unit
|
|
|
|
|
}
|
2019-02-25 13:56:18 +01:00
|
|
|
|
2020-05-20 13:51:59 -04:00
|
|
|
cuabrv := dwarf.DW_ABRV_COMPUNIT
|
|
|
|
|
if len(unit.Textp) == 0 {
|
|
|
|
|
cuabrv = dwarf.DW_ABRV_COMPUNIT_TEXTLESS
|
|
|
|
|
}
|
2021-07-01 09:27:46 -04:00
|
|
|
unit.DWInfo = d.newdie(&dwroot, cuabrv, unit.Lib.Pkg)
|
2019-08-09 11:36:03 -04:00
|
|
|
newattr(unit.DWInfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(dwarf.DW_LANG_Go), 0)
|
|
|
|
|
// OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
|
|
|
|
|
compDir := getCompilationDir()
|
|
|
|
|
// TODO: Make this be the actual compilation directory, not
|
|
|
|
|
// the linker directory. If we move CU construction into the
|
|
|
|
|
// compiler, this should happen naturally.
|
|
|
|
|
newattr(unit.DWInfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir)
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
var peData []byte
|
|
|
|
|
if producerExtra := d.ldr.Lookup(dwarf.CUInfoPrefix+"producer."+unit.Lib.Pkg, 0); producerExtra != 0 {
|
|
|
|
|
peData = d.ldr.Data(producerExtra)
|
|
|
|
|
}
|
2021-04-15 23:05:49 -04:00
|
|
|
producer := "Go cmd/compile " + buildcfg.Version
|
2019-11-20 10:43:11 -05:00
|
|
|
if len(peData) > 0 {
|
2019-08-09 11:36:03 -04:00
|
|
|
// We put a semicolon before the flags to clearly
|
|
|
|
|
// separate them from the version, which can be long
|
|
|
|
|
// and have lots of weird things in it in development
|
|
|
|
|
// versions. We promise not to put a semicolon in the
|
|
|
|
|
// version, so it should be safe for readers to scan
|
|
|
|
|
// forward to the semicolon.
|
2019-11-20 10:43:11 -05:00
|
|
|
producer += "; " + string(peData)
|
|
|
|
|
flagVariants[string(peData)] = true
|
2019-08-09 11:36:03 -04:00
|
|
|
} else {
|
|
|
|
|
flagVariants[""] = true
|
|
|
|
|
}
|
2018-09-25 11:52:24 +02:00
|
|
|
|
2019-08-09 11:36:03 -04:00
|
|
|
newattr(unit.DWInfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer)
|
2019-02-20 16:29:00 +01:00
|
|
|
|
2019-08-09 11:36:03 -04:00
|
|
|
var pkgname string
|
2019-11-20 10:43:11 -05:00
|
|
|
if pnSymIdx := d.ldr.Lookup(dwarf.CUInfoPrefix+"packagename."+unit.Lib.Pkg, 0); pnSymIdx != 0 {
|
|
|
|
|
pnsData := d.ldr.Data(pnSymIdx)
|
|
|
|
|
pkgname = string(pnsData)
|
2018-04-24 13:05:10 +02:00
|
|
|
}
|
2019-08-09 11:36:03 -04:00
|
|
|
newattr(unit.DWInfo, dwarf.DW_AT_go_package_name, dwarf.DW_CLS_STRING, int64(len(pkgname)), pkgname)
|
|
|
|
|
|
2020-05-20 15:06:22 -04:00
|
|
|
// Scan all functions in this compilation unit, create
|
|
|
|
|
// DIEs for all referenced types, find all referenced
|
|
|
|
|
// abstract functions, visit range symbols. Note that
|
|
|
|
|
// Textp has been dead-code-eliminated already.
|
|
|
|
|
for _, s := range unit.Textp {
|
|
|
|
|
d.dwarfVisitFunction(loader.Sym(s), unit)
|
2018-04-24 13:05:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-26 12:02:36 -04:00
|
|
|
// Fix for 31034: if the objects feeding into this link were compiled
|
|
|
|
|
// with different sets of flags, then don't issue an error if
|
|
|
|
|
// the -strictdups checks fail.
|
|
|
|
|
if checkStrictDups > 1 && len(flagVariants) > 1 {
|
|
|
|
|
checkStrictDups = 1
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-07 16:25:41 -05:00
|
|
|
// Make a pass through all data symbols, looking for those
|
|
|
|
|
// corresponding to reachable, Go-generated, user-visible
|
|
|
|
|
// global variables. For each global of this sort, locate
|
|
|
|
|
// the corresponding compiler-generated DIE symbol and tack
|
|
|
|
|
// it onto the list associated with the unit.
|
2021-09-03 17:00:41 +02:00
|
|
|
// Also looks for dictionary symbols and generates DIE symbols for each
|
|
|
|
|
// type they reference.
|
2019-11-20 10:43:11 -05:00
|
|
|
for idx := loader.Sym(1); idx < loader.Sym(d.ldr.NDef()); idx++ {
|
|
|
|
|
if !d.ldr.AttrReachable(idx) ||
|
|
|
|
|
d.ldr.AttrNotInSymbolTable(idx) ||
|
|
|
|
|
d.ldr.SymVersion(idx) >= sym.SymVerStatic {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
t := d.ldr.SymType(idx)
|
|
|
|
|
switch t {
|
|
|
|
|
case sym.SRODATA, sym.SDATA, sym.SNOPTRDATA, sym.STYPE, sym.SBSS, sym.SNOPTRBSS, sym.STLSBSS:
|
|
|
|
|
// ok
|
|
|
|
|
default:
|
|
|
|
|
continue
|
|
|
|
|
}
|
2021-09-03 17:00:41 +02:00
|
|
|
// Skip things with no type, unless it's a dictionary
|
2021-01-07 16:25:41 -05:00
|
|
|
gt := d.ldr.SymGoType(idx)
|
|
|
|
|
if gt == 0 {
|
2021-09-03 17:00:41 +02:00
|
|
|
if t == sym.SRODATA {
|
|
|
|
|
if d.ldr.IsDict(idx) {
|
|
|
|
|
// This is a dictionary, make sure that all types referenced by this dictionary are reachable
|
|
|
|
|
relocs := d.ldr.Relocs(idx)
|
|
|
|
|
for i := 0; i < relocs.Count(); i++ {
|
|
|
|
|
reloc := relocs.At(i)
|
|
|
|
|
if reloc.Type() == objabi.R_USEIFACE {
|
|
|
|
|
d.defgotype(reloc.Sym())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2020-06-30 10:22:13 -04:00
|
|
|
// Skip file local symbols (this includes static tmps, stack
|
|
|
|
|
// object symbols, and local symbols in assembler src files).
|
|
|
|
|
if d.ldr.IsFileLocal(idx) {
|
2019-11-20 10:43:11 -05:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-07 16:25:41 -05:00
|
|
|
// Find compiler-generated DWARF info sym for global in question,
|
|
|
|
|
// and tack it onto the appropriate unit. Note that there are
|
|
|
|
|
// circumstances under which we can't find the compiler-generated
|
|
|
|
|
// symbol-- this typically happens as a result of compiler options
|
|
|
|
|
// (e.g. compile package X with "-dwarf=0").
|
2023-04-28 21:35:31 -04:00
|
|
|
varDIE := d.ldr.GetVarDwarfAuxSym(idx)
|
2021-01-07 16:25:41 -05:00
|
|
|
if varDIE != 0 {
|
|
|
|
|
unit := d.ldr.SymUnit(idx)
|
|
|
|
|
d.defgotype(gt)
|
|
|
|
|
unit.VarDIEs = append(unit.VarDIEs, sym.LoaderSym(varDIE))
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
}
|
2018-09-25 11:52:24 +02:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
d.synthesizestringtypes(ctxt, dwtypes.Child)
|
|
|
|
|
d.synthesizeslicetypes(ctxt, dwtypes.Child)
|
|
|
|
|
d.synthesizemaptypes(ctxt, dwtypes.Child)
|
|
|
|
|
d.synthesizechantypes(ctxt, dwtypes.Child)
|
2018-04-24 13:05:10 +02:00
|
|
|
}
|
|
|
|
|
|
2020-06-10 10:05:37 -04:00
|
|
|
// dwarfGenerateDebugSyms constructs debug_line, debug_frame, and
|
|
|
|
|
// debug_loc. It also writes out the debug_info section using symbols
|
|
|
|
|
// generated in dwarfGenerateDebugInfo2.
|
2020-03-10 10:36:20 -04:00
|
|
|
func dwarfGenerateDebugSyms(ctxt *Link) {
|
2019-11-20 10:43:11 -05:00
|
|
|
if !dwarfEnabled(ctxt) {
|
|
|
|
|
return
|
2018-09-25 11:52:24 +02:00
|
|
|
}
|
2020-05-15 18:35:05 -04:00
|
|
|
d := &dwctxt{
|
2020-02-14 16:12:51 -05:00
|
|
|
linkctxt: ctxt,
|
|
|
|
|
ldr: ctxt.loader,
|
|
|
|
|
arch: ctxt.Arch,
|
2020-06-12 09:04:28 -04:00
|
|
|
dwmu: new(sync.Mutex),
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
|
|
|
|
d.dwarfGenerateDebugSyms()
|
2018-04-24 13:05:10 +02:00
|
|
|
}
|
2018-09-28 16:44:30 +02:00
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
// dwUnitSyms stores input and output symbols for DWARF generation
|
|
|
|
|
// for a given compilation unit.
|
|
|
|
|
type dwUnitSyms struct {
|
|
|
|
|
// Inputs for a given unit.
|
|
|
|
|
lineProlog loader.Sym
|
|
|
|
|
rangeProlog loader.Sym
|
|
|
|
|
infoEpilog loader.Sym
|
|
|
|
|
|
|
|
|
|
// Outputs for a given unit.
|
|
|
|
|
linesyms []loader.Sym
|
|
|
|
|
infosyms []loader.Sym
|
|
|
|
|
locsyms []loader.Sym
|
|
|
|
|
rangessyms []loader.Sym
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dwUnitPortion assembles the DWARF content for a given compilation
|
|
|
|
|
// unit: debug_info, debug_lines, debug_ranges, debug_loc (debug_frame
|
2023-06-13 23:01:11 +00:00
|
|
|
// is handled elsewhere). Order is important; the calls to writelines
|
2020-06-12 09:04:28 -04:00
|
|
|
// and writepcranges below make updates to the compilation unit DIE,
|
|
|
|
|
// hence they have to happen before the call to writeUnitInfo.
|
|
|
|
|
func (d *dwctxt) dwUnitPortion(u *sym.CompilationUnit, abbrevsym loader.Sym, us *dwUnitSyms) {
|
|
|
|
|
if u.DWInfo.Abbrev != dwarf.DW_ABRV_COMPUNIT_TEXTLESS {
|
2020-06-22 13:26:15 -04:00
|
|
|
us.linesyms = d.writelines(u, us.lineProlog)
|
2020-06-12 09:04:28 -04:00
|
|
|
base := loader.Sym(u.Textp[0])
|
|
|
|
|
us.rangessyms = d.writepcranges(u, base, u.PCs, us.rangeProlog)
|
|
|
|
|
us.locsyms = d.collectUnitLocs(u)
|
|
|
|
|
}
|
|
|
|
|
us.infosyms = d.writeUnitInfo(u, abbrevsym, us.infoEpilog)
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) dwarfGenerateDebugSyms() {
|
2020-04-17 09:11:57 -04:00
|
|
|
abbrevSec := d.writeabbrev()
|
2020-05-15 18:35:05 -04:00
|
|
|
dwarfp = append(dwarfp, abbrevSec)
|
2020-02-14 16:12:51 -05:00
|
|
|
d.calcCompUnitRanges()
|
2024-09-03 17:46:10 +00:00
|
|
|
slices.SortFunc(d.linkctxt.compUnits, compilationUnitByStartPCCmp)
|
2020-02-14 16:12:51 -05:00
|
|
|
|
|
|
|
|
// newdie adds DIEs to the *beginning* of the parent's DIE list.
|
|
|
|
|
// Now that we're done creating DIEs, reverse the trees so DIEs
|
|
|
|
|
// appear in the order they were created.
|
2020-06-12 09:04:28 -04:00
|
|
|
for _, u := range d.linkctxt.compUnits {
|
|
|
|
|
reversetree(&u.DWInfo.Child)
|
|
|
|
|
}
|
2020-02-14 16:12:51 -05:00
|
|
|
reversetree(&dwtypes.Child)
|
|
|
|
|
movetomodule(d.linkctxt, &dwtypes)
|
|
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
mkSecSym := func(name string) loader.Sym {
|
|
|
|
|
s := d.ldr.CreateSymForUpdate(name, 0)
|
|
|
|
|
s.SetType(sym.SDWARFSECT)
|
|
|
|
|
s.SetReachable(true)
|
|
|
|
|
return s.Sym()
|
|
|
|
|
}
|
|
|
|
|
mkAnonSym := func(kind sym.SymKind) loader.Sym {
|
|
|
|
|
s := d.ldr.MakeSymbolUpdater(d.ldr.CreateExtSym("", 0))
|
|
|
|
|
s.SetType(kind)
|
|
|
|
|
s.SetReachable(true)
|
|
|
|
|
return s.Sym()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the section symbols.
|
|
|
|
|
frameSym := mkSecSym(".debug_frame")
|
|
|
|
|
locSym := mkSecSym(".debug_loc")
|
|
|
|
|
lineSym := mkSecSym(".debug_line")
|
|
|
|
|
rangesSym := mkSecSym(".debug_ranges")
|
|
|
|
|
infoSym := mkSecSym(".debug_info")
|
|
|
|
|
|
|
|
|
|
// Create the section objects
|
|
|
|
|
lineSec := dwarfSecInfo{syms: []loader.Sym{lineSym}}
|
|
|
|
|
locSec := dwarfSecInfo{syms: []loader.Sym{locSym}}
|
|
|
|
|
rangesSec := dwarfSecInfo{syms: []loader.Sym{rangesSym}}
|
|
|
|
|
frameSec := dwarfSecInfo{syms: []loader.Sym{frameSym}}
|
|
|
|
|
infoSec := dwarfSecInfo{syms: []loader.Sym{infoSym}}
|
|
|
|
|
|
|
|
|
|
// Create any new symbols that will be needed during the
|
|
|
|
|
// parallel portion below.
|
|
|
|
|
ncu := len(d.linkctxt.compUnits)
|
|
|
|
|
unitSyms := make([]dwUnitSyms, ncu)
|
|
|
|
|
for i := 0; i < ncu; i++ {
|
|
|
|
|
us := &unitSyms[i]
|
|
|
|
|
us.lineProlog = mkAnonSym(sym.SDWARFLINES)
|
|
|
|
|
us.rangeProlog = mkAnonSym(sym.SDWARFRANGE)
|
|
|
|
|
us.infoEpilog = mkAnonSym(sym.SDWARFFCN)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
sema := make(chan struct{}, runtime.GOMAXPROCS(0))
|
|
|
|
|
|
|
|
|
|
// Kick off generation of .debug_frame, since it doesn't have
|
|
|
|
|
// any entanglements and can be started right away.
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
go func() {
|
|
|
|
|
sema <- struct{}{}
|
|
|
|
|
defer func() {
|
|
|
|
|
<-sema
|
|
|
|
|
wg.Done()
|
|
|
|
|
}()
|
|
|
|
|
frameSec = d.writeframes(frameSym)
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// Create a goroutine per comp unit to handle the generation that
|
|
|
|
|
// unit's portion of .debug_line, .debug_loc, .debug_ranges, and
|
|
|
|
|
// .debug_info.
|
|
|
|
|
wg.Add(len(d.linkctxt.compUnits))
|
|
|
|
|
for i := 0; i < ncu; i++ {
|
|
|
|
|
go func(u *sym.CompilationUnit, us *dwUnitSyms) {
|
|
|
|
|
sema <- struct{}{}
|
|
|
|
|
defer func() {
|
|
|
|
|
<-sema
|
|
|
|
|
wg.Done()
|
|
|
|
|
}()
|
|
|
|
|
d.dwUnitPortion(u, abbrevSec.secSym(), us)
|
|
|
|
|
}(d.linkctxt.compUnits[i], &unitSyms[i])
|
|
|
|
|
}
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
|
|
markReachable := func(syms []loader.Sym) []loader.Sym {
|
|
|
|
|
for _, s := range syms {
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(s, true)
|
|
|
|
|
d.ldr.SetAttrReachable(s, true)
|
|
|
|
|
}
|
|
|
|
|
return syms
|
|
|
|
|
}
|
2020-04-17 09:11:57 -04:00
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
// Stitch together the results.
|
|
|
|
|
for i := 0; i < ncu; i++ {
|
|
|
|
|
r := &unitSyms[i]
|
|
|
|
|
lineSec.syms = append(lineSec.syms, markReachable(r.linesyms)...)
|
|
|
|
|
infoSec.syms = append(infoSec.syms, markReachable(r.infosyms)...)
|
|
|
|
|
locSec.syms = append(locSec.syms, markReachable(r.locsyms)...)
|
|
|
|
|
rangesSec.syms = append(rangesSec.syms, markReachable(r.rangessyms)...)
|
|
|
|
|
}
|
|
|
|
|
dwarfp = append(dwarfp, lineSec)
|
2020-06-11 14:48:08 -04:00
|
|
|
dwarfp = append(dwarfp, frameSec)
|
2020-04-17 09:11:57 -04:00
|
|
|
gdbScriptSec := d.writegdbscript()
|
|
|
|
|
if gdbScriptSec.secSym() != 0 {
|
2020-05-15 18:35:05 -04:00
|
|
|
dwarfp = append(dwarfp, gdbScriptSec)
|
2020-04-17 09:11:57 -04:00
|
|
|
}
|
2020-05-15 18:35:05 -04:00
|
|
|
dwarfp = append(dwarfp, infoSec)
|
2020-06-12 09:04:28 -04:00
|
|
|
if len(locSec.syms) > 1 {
|
2020-05-15 18:35:05 -04:00
|
|
|
dwarfp = append(dwarfp, locSec)
|
2020-04-17 09:11:57 -04:00
|
|
|
}
|
2020-06-12 09:04:28 -04:00
|
|
|
dwarfp = append(dwarfp, rangesSec)
|
2020-04-17 09:11:57 -04:00
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
// Check to make sure we haven't listed any symbols more than once
|
|
|
|
|
// in the info section. This used to be done by setting and
|
|
|
|
|
// checking the OnList attribute in "putdie", but that strategy
|
|
|
|
|
// was not friendly for concurrency.
|
|
|
|
|
seen := loader.MakeBitmap(d.ldr.NSym())
|
|
|
|
|
for _, s := range infoSec.syms {
|
|
|
|
|
if seen.Has(s) {
|
2024-06-27 14:54:06 +00:00
|
|
|
log.Fatalf("dwarf symbol %s listed multiple times",
|
|
|
|
|
d.ldr.SymName(s))
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
2020-06-12 09:04:28 -04:00
|
|
|
seen.Set(s)
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-12 09:04:28 -04:00
|
|
|
func (d *dwctxt) collectUnitLocs(u *sym.CompilationUnit) []loader.Sym {
|
|
|
|
|
syms := []loader.Sym{}
|
2020-06-11 14:48:08 -04:00
|
|
|
for _, fn := range u.FuncDIEs {
|
|
|
|
|
relocs := d.ldr.Relocs(loader.Sym(fn))
|
|
|
|
|
for i := 0; i < relocs.Count(); i++ {
|
2020-07-29 13:26:50 -04:00
|
|
|
reloc := relocs.At(i)
|
2020-06-11 14:48:08 -04:00
|
|
|
if reloc.Type() != objabi.R_DWARFSECREF {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
rsym := reloc.Sym()
|
|
|
|
|
if d.ldr.SymType(rsym) == sym.SDWARFLOC {
|
|
|
|
|
syms = append(syms, rsym)
|
|
|
|
|
// One location list entry per function, but many relocations to it. Don't duplicate.
|
|
|
|
|
break
|
2020-02-14 16:12:51 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-11 14:48:08 -04:00
|
|
|
return syms
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-04 17:09:49 -04:00
|
|
|
// Add DWARF section names to the section header string table, by calling add
|
|
|
|
|
// on each name. ELF only.
|
|
|
|
|
func dwarfaddshstrings(ctxt *Link, add func(string)) {
|
2020-06-10 09:57:10 -04:00
|
|
|
if *FlagW { // disable dwarf
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-10 10:05:37 -04:00
|
|
|
secs := []string{"abbrev", "frame", "info", "loc", "line", "gdb_scripts", "ranges"}
|
2020-06-10 09:57:10 -04:00
|
|
|
for _, sec := range secs {
|
2023-05-04 17:09:49 -04:00
|
|
|
add(".debug_" + sec)
|
2020-06-10 09:57:10 -04:00
|
|
|
if ctxt.IsExternal() {
|
2023-05-04 17:09:49 -04:00
|
|
|
add(elfRelType + ".debug_" + sec)
|
2020-06-10 09:57:10 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func dwarfaddelfsectionsyms(ctxt *Link) {
|
|
|
|
|
if *FlagW { // disable dwarf
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if ctxt.LinkMode != LinkExternal {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ldr := ctxt.loader
|
|
|
|
|
for _, si := range dwarfp {
|
|
|
|
|
s := si.secSym()
|
|
|
|
|
sect := ldr.SymSect(si.secSym())
|
|
|
|
|
putelfsectionsym(ctxt, ctxt.Out, 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 dwarfp {
|
|
|
|
|
go func(resIndex int, syms []loader.Sym) {
|
|
|
|
|
resChannel <- compressedSect{resIndex, compressSyms(ctxt, syms), syms}
|
|
|
|
|
}(compressedCount, dwarfp[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 {
|
2022-01-26 10:23:48 +08:00
|
|
|
var compressedSegName string
|
|
|
|
|
if ctxt.IsELF {
|
|
|
|
|
compressedSegName = ldr.SymSect(s).Name
|
|
|
|
|
} else {
|
|
|
|
|
compressedSegName = ".zdebug_" + ldr.SymSect(s).Name[len(".debug_"):]
|
|
|
|
|
}
|
2020-06-10 09:57:10 -04:00
|
|
|
sect := addsection(ctxt.loader, ctxt.Arch, &Segdwarf, compressedSegName, 04)
|
2022-03-18 17:36:52 +08:00
|
|
|
sect.Align = int32(ctxt.Arch.Alignment)
|
2020-06-10 09:57:10 -04:00
|
|
|
sect.Length = uint64(len(z.compressed))
|
2022-01-26 10:23:48 +08:00
|
|
|
sect.Compressed = true
|
|
|
|
|
newSym := ldr.MakeSymbolBuilder(compressedSegName)
|
|
|
|
|
ldr.SetAttrReachable(s, true)
|
2020-06-10 09:57:10 -04:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dwarfp = 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 dwarfp {
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-03 17:46:10 +00:00
|
|
|
func compilationUnitByStartPCCmp(a, b *sym.CompilationUnit) int {
|
2020-06-10 09:57:10 -04:00
|
|
|
switch {
|
2024-09-03 17:46:10 +00:00
|
|
|
case len(a.Textp) == 0 && len(b.Textp) == 0:
|
|
|
|
|
return strings.Compare(a.Lib.Pkg, b.Lib.Pkg)
|
|
|
|
|
case len(a.Textp) != 0 && len(b.Textp) == 0:
|
|
|
|
|
return -1
|
|
|
|
|
case len(a.Textp) == 0 && len(b.Textp) != 0:
|
|
|
|
|
return +1
|
2020-06-10 09:57:10 -04:00
|
|
|
default:
|
2024-09-03 17:46:10 +00:00
|
|
|
return cmp.Compare(a.PCs[0].Start, b.PCs[0].Start)
|
2020-06-10 09:57:10 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-14 16:12:51 -05:00
|
|
|
// getPkgFromCUSym returns the package name for the compilation unit
|
|
|
|
|
// represented by s.
|
|
|
|
|
// The prefix dwarf.InfoPrefix+".pkg." needs to be removed in order to get
|
|
|
|
|
// the package name.
|
2020-05-15 18:35:05 -04:00
|
|
|
func (d *dwctxt) getPkgFromCUSym(s loader.Sym) string {
|
2020-02-14 16:12:51 -05:00
|
|
|
return strings.TrimPrefix(d.ldr.SymName(s), dwarf.InfoPrefix+".pkg.")
|
|
|
|
|
}
|
2020-03-10 10:36:20 -04:00
|
|
|
|
|
|
|
|
// On AIX, the symbol table needs to know where are the compilation units parts
|
|
|
|
|
// for a specific package in each .dw section.
|
|
|
|
|
// dwsectCUSize map will save the size of a compilation unit for
|
|
|
|
|
// the corresponding .dw section.
|
|
|
|
|
// This size can later be retrieved with the index "sectionName.pkgName".
|
2020-06-12 09:04:28 -04:00
|
|
|
var dwsectCUSizeMu sync.Mutex
|
2020-03-10 10:36:20 -04:00
|
|
|
var dwsectCUSize map[string]uint64
|
|
|
|
|
|
|
|
|
|
// getDwsectCUSize retrieves the corresponding package size inside the current section.
|
|
|
|
|
func getDwsectCUSize(sname string, pkgname string) uint64 {
|
|
|
|
|
return dwsectCUSize[sname+"."+pkgname]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func addDwsectCUSize(sname string, pkgname string, size uint64) {
|
2020-06-12 09:04:28 -04:00
|
|
|
dwsectCUSizeMu.Lock()
|
|
|
|
|
defer dwsectCUSizeMu.Unlock()
|
2020-03-10 10:36:20 -04:00
|
|
|
dwsectCUSize[sname+"."+pkgname] += size
|
|
|
|
|
}
|