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"
|
2015-02-27 22:57:28 -05:00
|
|
|
"fmt"
|
2016-03-14 09:23:04 -07:00
|
|
|
"log"
|
2020-02-14 16:12:51 -05:00
|
|
|
"sort"
|
2015-02-27 22:57:28 -05:00
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// dwctxt2 is a wrapper intended to satisfy the method set of
|
|
|
|
|
// 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).
|
|
|
|
|
type dwctxt2 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
|
|
|
|
|
// the DWARF DIE for that type (e.g. "go.info.type.uintptr")
|
|
|
|
|
tmap map[string]loader.Sym
|
|
|
|
|
|
|
|
|
|
// This maps loader symbol for the DWARF DIE symbol generated for
|
|
|
|
|
// a type (e.g. "go.info.uintptr") to the type symbol itself
|
|
|
|
|
// ("type.uintptr").
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
|
|
// 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")
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newdwctxt2(linkctxt *Link, forTypeGen bool) dwctxt2 {
|
|
|
|
|
d := dwctxt2{
|
|
|
|
|
linkctxt: linkctxt,
|
|
|
|
|
ldr: linkctxt.loader,
|
|
|
|
|
arch: linkctxt.Arch,
|
|
|
|
|
tmap: make(map[string]loader.Sym),
|
|
|
|
|
tdmap: make(map[loader.Sym]loader.Sym),
|
|
|
|
|
rtmap: make(map[loader.Sym]loader.Sym),
|
|
|
|
|
}
|
|
|
|
|
d.typeRuntimeEface = d.lookupOrDiag("type.runtime.eface")
|
|
|
|
|
d.typeRuntimeIface = d.lookupOrDiag("type.runtime.iface")
|
|
|
|
|
return d
|
2016-08-19 22:40:38 -04:00
|
|
|
}
|
2016-03-14 09:23:04 -07: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
|
|
|
|
|
|
|
|
|
|
func (s dwSym) Length(dwarfContext interface{}) int64 {
|
|
|
|
|
l := dwarfContext.(dwctxt2).ldr
|
|
|
|
|
return int64(len(l.Data(loader.Sym(s))))
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (c dwctxt2) PtrSize() int {
|
|
|
|
|
return c.arch.PtrSize
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
|
|
|
|
|
func (c dwctxt2) 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
|
|
|
|
|
|
|
|
func (c dwctxt2) 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
|
|
|
|
|
|
|
|
func (c dwctxt2) 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
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (c dwctxt2) 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
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (c dwctxt2) 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
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (c dwctxt2) 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)
|
2016-07-28 13:04:41 -04:00
|
|
|
fallthrough
|
2019-11-20 10:43:11 -05:00
|
|
|
case c.arch.PtrSize:
|
2020-02-19 16:16:17 -05:00
|
|
|
dsu.AddAddrPlus(c.arch, tds, 0)
|
2016-07-28 13:04:41 -04:00
|
|
|
case 4:
|
2020-02-19 16:16:17 -05:00
|
|
|
dsu.AddAddrPlus4(c.arch, tds, 0)
|
2016-07-28 13:04:41 -04:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
rsl := dsu.Relocs()
|
|
|
|
|
r := &rsl[len(rsl)-1]
|
2018-04-12 17:07:14 -04:00
|
|
|
r.Type = objabi.R_ADDROFF
|
2016-07-28 13:04:41 -04:00
|
|
|
r.Add = ofs
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (c dwctxt2) AddDWARFAddrSectionOffset(s dwarf.Sym, t interface{}, ofs int64) {
|
2018-09-28 16:44:30 +02:00
|
|
|
size := 4
|
|
|
|
|
if isDwarf64(c.linkctxt) {
|
|
|
|
|
size = 8
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-12 17:07:14 -04:00
|
|
|
c.AddSectionOffset(s, size, t, ofs)
|
2019-11-20 10:43:11 -05:00
|
|
|
|
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
|
|
|
rsl := dsu.Relocs()
|
|
|
|
|
r := &rsl[len(rsl)-1]
|
|
|
|
|
r.Type = objabi.R_DWARFSECREF
|
2018-04-12 17:07:14 -04:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (c dwctxt2) 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.
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (c dwctxt2) AddFileRef(s dwarf.Sym, f interface{}) {
|
2017-10-24 16:08:46 -04:00
|
|
|
panic("should be used only in the compiler")
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (c dwctxt2) CurrentOffset(s dwarf.Sym) int64 {
|
2017-10-06 11:32:28 -04:00
|
|
|
panic("should be used only in the compiler")
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (c dwctxt2) 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")
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (c dwctxt2) 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")
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
var gdbscript string
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
var dwarfp2 []loader.Sym
|
2016-03-14 09:23:04 -07:00
|
|
|
|
2020-02-14 16:12:51 -05:00
|
|
|
func (d *dwctxt2) writeabbrev() loader.Sym {
|
|
|
|
|
abrvs := d.ldr.AddExtSym(".debug_abbrev", 0)
|
|
|
|
|
u := d.ldr.MakeSymbolUpdater(abrvs)
|
|
|
|
|
u.SetType(sym.SDWARFSECT)
|
|
|
|
|
u.AddBytes(dwarf.GetAbbrev())
|
|
|
|
|
return abrvs
|
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).
|
2016-07-28 13:04:41 -04:00
|
|
|
func newattr(die *dwarf.DWDie, attr uint16, cls int, value int64, data interface{}) *dwarf.DWAttr {
|
|
|
|
|
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
|
|
|
return a
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
func (d *dwctxt2) newdie(parent *dwarf.DWDie, abbrev int, name string, version int) *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)
|
|
|
|
|
|
|
|
|
|
if name != "" && (abbrev <= dwarf.DW_ABRV_VARIABLE || abbrev >= dwarf.DW_ABRV_NULLTYPE) {
|
2019-11-20 10:43:11 -05:00
|
|
|
// Q: do we need version here? My understanding is that all these
|
|
|
|
|
// symbols should be version 0.
|
2016-07-28 13:04:41 -04:00
|
|
|
if abbrev != dwarf.DW_ABRV_VARIABLE || version == 0 {
|
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
|
|
|
if abbrev == dwarf.DW_ABRV_COMPUNIT {
|
|
|
|
|
// Avoid collisions with "real" symbol names.
|
2019-11-20 10:43:11 -05:00
|
|
|
name = fmt.Sprintf(".pkg.%s.%d", name, len(d.linkctxt.compUnits))
|
|
|
|
|
}
|
|
|
|
|
ds := d.ldr.LookupOrCreateSym(dwarf.InfoPrefix+name, version)
|
|
|
|
|
dsu := d.ldr.MakeSymbolUpdater(ds)
|
|
|
|
|
dsu.SetType(sym.SDWARFINFO)
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(ds, true)
|
|
|
|
|
d.ldr.SetAttrReachable(ds, true)
|
2020-02-19 16:16:17 -05:00
|
|
|
die.Sym = dwSym(ds)
|
2019-11-20 10:43:11 -05:00
|
|
|
if abbrev >= dwarf.DW_ABRV_NULLTYPE && abbrev <= dwarf.DW_ABRV_TYPEDECL {
|
|
|
|
|
d.tmap[name] = ds
|
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
|
|
|
}
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) walksymtypedef(symIdx loader.Sym) loader.Sym {
|
|
|
|
|
|
|
|
|
|
// We're being given the loader symbol for the type DIE, e.g.
|
|
|
|
|
// "go.info.type.uintptr". Map that first to the type symbol (e.g.
|
|
|
|
|
// "type.uintptr") and then to the typedef DIE for the type.
|
|
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-07 18:00:57 +03:00
|
|
|
// Used to avoid string allocation when looking up dwarf symbols
|
2016-07-28 13:04:41 -04:00
|
|
|
var prefixBuf = []byte(dwarf.InfoPrefix)
|
2016-04-07 18:00:57 +03:00
|
|
|
|
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.
|
|
|
|
|
func (d *dwctxt2) find(name string) loader.Sym {
|
|
|
|
|
return d.tmap[name]
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) mustFind(name string) loader.Sym {
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) adddwarfref(sb *loader.SymbolBuilder, t loader.Sym, size int) int64 {
|
2016-03-14 09:23:04 -07:00
|
|
|
var result int64
|
|
|
|
|
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)
|
2016-03-14 09:23:04 -07:00
|
|
|
fallthrough
|
2019-11-20 10:43:11 -05:00
|
|
|
case d.arch.PtrSize:
|
|
|
|
|
result = sb.AddAddrPlus(d.arch, t, 0)
|
2016-03-14 09:23:04 -07:00
|
|
|
case 4:
|
2019-11-20 10:43:11 -05:00
|
|
|
result = sb.AddAddrPlus4(d.arch, t, 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
rsl := sb.Relocs()
|
|
|
|
|
r := &rsl[len(rsl)-1]
|
2017-10-24 16:08:46 -04:00
|
|
|
r.Type = objabi.R_DWARFSECREF
|
2016-03-14 09:23:04 -07:00
|
|
|
return result
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) newrefattr(die *dwarf.DWDie, attr uint16, ref loader.Sym) *dwarf.DWAttr {
|
|
|
|
|
if ref == 0 {
|
2015-02-27 22:57:28 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
2020-02-19 16:16:17 -05:00
|
|
|
return newattr(die, attr, dwarf.DW_CLS_REFERENCE, 0, dwSym(ref))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) 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
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) 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 {
|
|
|
|
|
if d.ldr.AttrOnList(s) {
|
|
|
|
|
log.Fatalf("symbol %s listed multiple times", d.ldr.SymName(s))
|
|
|
|
|
}
|
|
|
|
|
d.ldr.SetAttrOnList(s, true)
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
// GDB doesn't like FORM_addr for AT_location, so emit a
|
2015-02-27 22:57:28 -05:00
|
|
|
// location expression that evals to a const.
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) newabslocexprattr(die *dwarf.DWDie, addr int64, symIdx loader.Sym) {
|
2020-02-19 16:16:17 -05:00
|
|
|
newattr(die, dwarf.DW_AT_location, dwarf.DW_CLS_ADDRESS, addr, dwSym(symIdx))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) lookupOrDiag(n string) loader.Sym {
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) dotypedef(parent *dwarf.DWDie, gotype loader.Sym, 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
|
|
|
}
|
|
|
|
|
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).
|
|
|
|
|
tds := d.ldr.CreateExtSym("")
|
|
|
|
|
tdsu := d.ldr.MakeSymbolUpdater(tds)
|
|
|
|
|
tdsu.SetType(sym.SDWARFINFO)
|
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.
|
2019-11-20 10:43:11 -05:00
|
|
|
die := d.newdie(parent, dwarf.DW_ABRV_TYPEDECL, name, 0)
|
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.
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) defgotype(gotype loader.Sym) loader.Sym {
|
|
|
|
|
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)
|
|
|
|
|
if !strings.HasPrefix(sn, "type.") {
|
|
|
|
|
d.linkctxt.Errorf(gotype, "dwarf: type name doesn't start with \"type.\"")
|
|
|
|
|
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
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) newtype(gotype loader.Sym) *dwarf.DWDie {
|
|
|
|
|
sn := d.ldr.SymName(gotype)
|
|
|
|
|
name := sn[5:] // could also decode from Type.string
|
|
|
|
|
tdata := d.ldr.Data(gotype)
|
|
|
|
|
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
|
2015-02-27 22:57:28 -05:00
|
|
|
switch kind {
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindBool:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
|
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
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindInt,
|
|
|
|
|
objabi.KindInt8,
|
|
|
|
|
objabi.KindInt16,
|
|
|
|
|
objabi.KindInt32,
|
|
|
|
|
objabi.KindInt64:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
|
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
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindUint,
|
|
|
|
|
objabi.KindUint8,
|
|
|
|
|
objabi.KindUint16,
|
|
|
|
|
objabi.KindUint32,
|
|
|
|
|
objabi.KindUint64,
|
|
|
|
|
objabi.KindUintptr:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
|
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
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindFloat32,
|
|
|
|
|
objabi.KindFloat64:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
|
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
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindComplex64,
|
|
|
|
|
objabi.KindComplex128:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BASETYPE, name, 0)
|
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
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindArray:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_ARRAYTYPE, name, 0)
|
|
|
|
|
typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
s := decodetypeArrayElem2(d.ldr, d.arch, gotype)
|
|
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
|
|
|
|
|
fld := d.newdie(die, dwarf.DW_ABRV_ARRAYRANGE, "range", 0)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// use actual length not upper bound; correct for 0-length arrays.
|
2019-11-20 10:43:11 -05:00
|
|
|
newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, decodetypeArrayLen2(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
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindChan:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_CHANTYPE, name, 0)
|
|
|
|
|
s := decodetypeChanElem2(d.ldr, d.arch, gotype)
|
|
|
|
|
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
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindFunc:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
|
2017-08-14 15:07:57 -07:00
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
|
|
|
|
|
data := d.ldr.Data(gotype)
|
|
|
|
|
// FIXME: add caching or reuse reloc slice.
|
|
|
|
|
relocs := d.ldr.Relocs(gotype)
|
|
|
|
|
rslice := relocs.ReadAll(nil)
|
|
|
|
|
nfields := decodetypeFuncInCount(d.arch, data)
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < nfields; i++ {
|
2019-11-20 10:43:11 -05:00
|
|
|
s := decodetypeFuncInType2(d.ldr, d.arch, gotype, rslice, i)
|
|
|
|
|
sn := d.ldr.SymName(s)
|
|
|
|
|
fld := d.newdie(die, dwarf.DW_ABRV_FUNCTYPEPARAM, sn[5:], 0)
|
|
|
|
|
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) {
|
|
|
|
|
d.newdie(die, dwarf.DW_ABRV_DOTDOTDOT, "...", 0)
|
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++ {
|
2019-11-20 10:43:11 -05:00
|
|
|
s := decodetypeFuncOutType2(d.ldr, d.arch, gotype, rslice, i)
|
|
|
|
|
sn := d.ldr.SymName(s)
|
|
|
|
|
fld := d.newdie(die, dwarf.DW_ABRV_FUNCTYPEPARAM, sn[5:], 0)
|
|
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.defptrto(d.defgotype(s)))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindInterface:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0)
|
|
|
|
|
typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
|
|
|
|
|
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
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindMap:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_MAPTYPE, name, 0)
|
|
|
|
|
s := decodetypeMapKey2(d.ldr, d.arch, gotype)
|
|
|
|
|
d.newrefattr(die, dwarf.DW_AT_go_key, d.defgotype(s))
|
|
|
|
|
s = decodetypeMapValue2(d.ldr, d.arch, gotype)
|
|
|
|
|
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
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindPtr:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_PTRTYPE, name, 0)
|
|
|
|
|
typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
|
|
|
|
|
s := decodetypePtrElem2(d.ldr, d.arch, gotype)
|
|
|
|
|
d.newrefattr(die, dwarf.DW_AT_type, d.defgotype(s))
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindSlice:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_SLICETYPE, name, 0)
|
|
|
|
|
typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
s := decodetypeArrayElem2(d.ldr, d.arch, gotype)
|
|
|
|
|
elem := d.defgotype(s)
|
|
|
|
|
d.newrefattr(die, dwarf.DW_AT_go_elem, elem)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindString:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_STRINGTYPE, name, 0)
|
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
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindStruct:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_STRUCTTYPE, name, 0)
|
|
|
|
|
typedefdie = d.dotypedef(&dwtypes, gotype, name, die)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
nfields := decodetypeStructFieldCount2(d.ldr, d.arch, gotype)
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < nfields; i++ {
|
2019-11-20 10:43:11 -05:00
|
|
|
f := decodetypeStructFieldName2(d.ldr, d.arch, gotype, i)
|
|
|
|
|
s := decodetypeStructFieldType2(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)
|
|
|
|
|
f = sn[5:] // skip "type."
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
fld := d.newdie(die, dwarf.DW_ABRV_STRUCTFIELD, f, 0)
|
|
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.defgotype(s))
|
|
|
|
|
offsetAnon := decodetypeStructFieldOffsAnon2(d.ldr, d.arch, gotype, i)
|
2017-04-26 17:58:31 -04:00
|
|
|
newmemberoffsetattr(fld, int32(offsetAnon>>1))
|
|
|
|
|
if offsetAnon&1 != 0 { // is embedded field
|
|
|
|
|
newattr(fld, dwarf.DW_AT_go_embedded_field, dwarf.DW_CLS_FLAG, 1, 0)
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
case objabi.KindUnsafePointer:
|
2019-11-20 10:43:11 -05:00
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, name, 0)
|
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)
|
|
|
|
|
die = d.newdie(&dwtypes, dwarf.DW_ABRV_TYPEDECL, name, 0)
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) nameFromDIESym(dwtypeDIESym loader.Sym) string {
|
|
|
|
|
sn := d.ldr.SymName(dwtypeDIESym)
|
|
|
|
|
return sn[len(dwarf.InfoPrefix):]
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) defptrto(dwtype loader.Sym) loader.Sym {
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
pdie := d.newdie(&dwtypes, dwarf.DW_ABRV_PTRTYPE, ptrname, 0)
|
|
|
|
|
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.
|
2019-11-20 10:43:11 -05:00
|
|
|
gts := d.ldr.Lookup("type."+ptrname, 0)
|
|
|
|
|
if gts != 0 && d.ldr.AttrReachable(gts) {
|
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.
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) 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
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
c := d.newdie(dst, src.Abbrev, getattr(src, dwarf.DW_AT_name).Data.(string), 0)
|
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
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) copychildren(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie) {
|
|
|
|
|
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
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) 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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) 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 {
|
|
|
|
|
log.Fatalf("internal error: DIE generation failed for %s\n", name)
|
|
|
|
|
}
|
2016-03-14 09:23:04 -07:00
|
|
|
return die
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) synthesizestringtypes(ctxt *Link, die *dwarf.DWDie) {
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) synthesizeslicetypes(ctxt *Link, die *dwarf.DWDie) {
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// synthesizemaptypes is way too closely married to runtime/hashmap.c
|
|
|
|
|
const (
|
|
|
|
|
MaxKeySize = 128
|
|
|
|
|
MaxValSize = 128
|
|
|
|
|
BucketSize = 8
|
|
|
|
|
)
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) 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)
|
|
|
|
|
if s != 0 && d.ldr.SymType(s) == sym.SDWARFINFO {
|
2016-03-14 09:23:04 -07:00
|
|
|
return s
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
die := d.newdie(&dwtypes, abbrev, name, 0)
|
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
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
|
|
|
|
|
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))
|
2019-11-20 10:43:11 -05:00
|
|
|
keytype := decodetypeMapKey2(d.ldr, d.arch, gotype)
|
|
|
|
|
valtype := decodetypeMapValue2(d.ldr, d.arch, gotype)
|
|
|
|
|
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
|
2015-02-27 22:57:28 -05:00
|
|
|
if keysize > MaxKeySize {
|
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
|
|
|
}
|
|
|
|
|
if valsize > MaxValSize {
|
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) {
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(dwhk, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize*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)
|
2016-08-19 22:40:38 -04:00
|
|
|
fld := newdie(ctxt, dwhk, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, BucketSize, 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) {
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(dwhv, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize*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)
|
2016-08-19 22:40:38 -04:00
|
|
|
fld := newdie(ctxt, dwhv, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, BucketSize, 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
|
|
|
|
2016-08-19 22:40:38 -04:00
|
|
|
fld := newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "keys", 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, dwhks)
|
2016-03-14 09:23:04 -07:00
|
|
|
newmemberoffsetattr(fld, BucketSize)
|
2016-08-19 22:40:38 -04:00
|
|
|
fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "values", 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, dwhvs)
|
2016-03-14 09:23:04 -07:00
|
|
|
newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize))
|
2016-08-19 22:40:38 -04:00
|
|
|
fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "overflow", 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.defptrto(d.dtolsym(dwhb.Sym)))
|
2016-03-14 09:23:04 -07:00
|
|
|
newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
|
2019-11-20 10:43:11 -05:00
|
|
|
if d.arch.RegSize > d.arch.PtrSize {
|
2016-08-19 22:40:38 -04:00
|
|
|
fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "pad", 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
|
|
|
|
|
newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(d.arch.PtrSize))
|
2016-03-14 09:23:04 -07:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
newattr(dwhb, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize+BucketSize*keysize+BucketSize*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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) synthesizechantypes(ctxt *Link, die *dwarf.DWDie) {
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) dwarfDefineGlobal(ctxt *Link, symIdx loader.Sym, str string, v int64, gotype loader.Sym) {
|
2019-08-09 11:36:03 -04:00
|
|
|
// Find a suitable CU DIE to include the global.
|
|
|
|
|
// One would think it's as simple as just looking at the unit, but that might
|
|
|
|
|
// not have any reachable code. So, we go to the runtime's CU if our unit
|
|
|
|
|
// isn't otherwise reachable.
|
2019-11-20 10:43:11 -05:00
|
|
|
unit := d.ldr.SymUnit(symIdx)
|
|
|
|
|
if unit == nil {
|
2019-08-09 11:36:03 -04:00
|
|
|
unit = ctxt.runtimeCU
|
2018-09-25 11:52:24 +02:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
ver := d.ldr.SymVersion(symIdx)
|
|
|
|
|
dv := d.newdie(unit.DWInfo, dwarf.DW_ABRV_VARIABLE, str, int(ver))
|
|
|
|
|
d.newabslocexprattr(dv, v, symIdx)
|
|
|
|
|
if d.ldr.SymVersion(symIdx) < sym.SymVerStatic {
|
2018-04-24 13:05:10 +02:00
|
|
|
newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0)
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
dt := d.defgotype(gotype)
|
|
|
|
|
d.newrefattr(dv, dwarf.DW_AT_type, dt)
|
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-02-14 16:12:51 -05:00
|
|
|
func (d *dwctxt2) createUnitLength(su *loader.SymbolBuilder, v uint64) {
|
|
|
|
|
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-02-14 16:12:51 -05:00
|
|
|
func (d *dwctxt2) addDwarfAddrField(sb *loader.SymbolBuilder, v uint64) {
|
|
|
|
|
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-02-14 16:12:51 -05:00
|
|
|
func (d *dwctxt2) addDwarfAddrRef(sb *loader.SymbolBuilder, t loader.Sym) {
|
|
|
|
|
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-02-14 16:12:51 -05:00
|
|
|
func (d *dwctxt2) calcCompUnitRanges() {
|
|
|
|
|
var prevUnit *sym.CompilationUnit
|
|
|
|
|
for _, s := range d.linkctxt.Textp2 {
|
|
|
|
|
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)
|
|
|
|
|
u0val := d.ldr.SymValue(loader.Sym(unit.Textp2[0]))
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) importInfoSymbol(ctxt *Link, dsym loader.Sym) {
|
|
|
|
|
d.ldr.SetAttrReachable(dsym, true)
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(dsym, true)
|
|
|
|
|
if d.ldr.SymType(dsym) != sym.SDWARFINFO {
|
|
|
|
|
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
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
drelocs := d.ldr.Relocs(dsym)
|
|
|
|
|
rslice := drelocs.ReadSyms(nil)
|
|
|
|
|
for i := 0; i < len(rslice); i++ {
|
|
|
|
|
r := &rslice[i]
|
|
|
|
|
if r.Type != objabi.R_DWARFSECREF {
|
|
|
|
|
continue
|
2018-02-13 17:39:38 -05:00
|
|
|
}
|
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.
|
|
|
|
|
if _, ok := d.rtmap[r.Sym]; ok {
|
|
|
|
|
// 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?
|
|
|
|
|
sn := d.ldr.SymName(r.Sym)
|
|
|
|
|
tn := sn[len(dwarf.InfoPrefix):]
|
|
|
|
|
ts := d.ldr.Lookup("type."+tn, 0)
|
|
|
|
|
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 {
|
|
|
|
|
if strings.HasPrefix(fname, src.FileSymPrefix) {
|
|
|
|
|
fname = fname[len(src.FileSymPrefix):]
|
|
|
|
|
}
|
|
|
|
|
return expandGoroot(fname)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func expandFileSym(l *loader.Loader, fsym loader.Sym) string {
|
|
|
|
|
return expandFile(l.SymName(fsym))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *dwctxt2) writelines(unit *sym.CompilationUnit, ls loader.Sym) {
|
|
|
|
|
|
|
|
|
|
is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles.
|
|
|
|
|
|
|
|
|
|
unitstart := int64(-1)
|
|
|
|
|
headerstart := int64(-1)
|
|
|
|
|
headerend := int64(-1)
|
|
|
|
|
|
|
|
|
|
lsu := d.ldr.MakeSymbolUpdater(ls)
|
|
|
|
|
newattr(unit.DWInfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, lsu.Size(), dwSym(ls))
|
|
|
|
|
|
|
|
|
|
// 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]
|
|
|
|
|
lsu.AddUint8(0) // include_directories (empty)
|
|
|
|
|
|
|
|
|
|
// Maps loader.Sym for file symbol to expanded filename.
|
|
|
|
|
expandedFiles := make(map[loader.Sym]string)
|
|
|
|
|
|
|
|
|
|
// Copy over the file table.
|
|
|
|
|
fileNums := make(map[string]int)
|
|
|
|
|
lsDwsym := dwSym(ls)
|
|
|
|
|
for i, name := range unit.DWARFFileTable {
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
fileNums[name] = i + 1
|
|
|
|
|
d.AddString(lsDwsym, name)
|
|
|
|
|
lsu.AddUint8(0)
|
|
|
|
|
lsu.AddUint8(0)
|
|
|
|
|
lsu.AddUint8(0)
|
|
|
|
|
if gdbscript == "" {
|
|
|
|
|
// 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.
|
|
|
|
|
if i := strings.Index(name, "runtime/proc.go"); i >= 0 {
|
|
|
|
|
k := strings.Index(name, "runtime/proc.go")
|
|
|
|
|
gdbscript = name[:k] + "runtime/runtime-gdb.py"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Grab files for inlined functions.
|
|
|
|
|
// TODO: With difficulty, this could be moved into the compiler.
|
|
|
|
|
for _, s := range unit.Textp2 {
|
|
|
|
|
fnSym := loader.Sym(s)
|
|
|
|
|
infosym, _, _, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
|
|
|
|
|
drelocs := d.ldr.Relocs(infosym)
|
|
|
|
|
rslice := drelocs.ReadSyms(nil)
|
|
|
|
|
for ri := 0; ri < len(rslice); ri++ {
|
|
|
|
|
r := &rslice[ri]
|
|
|
|
|
if r.Type != objabi.R_DWARFFILEREF {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
fname, ok := expandedFiles[r.Sym]
|
|
|
|
|
if !ok {
|
|
|
|
|
fname = expandFileSym(d.ldr, r.Sym)
|
|
|
|
|
expandedFiles[r.Sym] = fname
|
|
|
|
|
}
|
|
|
|
|
if _, ok := fileNums[fname]; ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
fileNums[fname] = len(fileNums) + 1
|
|
|
|
|
d.AddString(lsDwsym, fname)
|
|
|
|
|
lsu.AddUint8(0)
|
|
|
|
|
lsu.AddUint8(0)
|
|
|
|
|
lsu.AddUint8(0)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4 zeros: the string termination + 3 fields.
|
|
|
|
|
lsu.AddUint8(0)
|
|
|
|
|
// terminate file_names.
|
|
|
|
|
headerend = lsu.Size()
|
|
|
|
|
|
|
|
|
|
// Output the state machine for each function remaining.
|
|
|
|
|
var lastAddr int64
|
|
|
|
|
for _, s := range unit.Textp2 {
|
|
|
|
|
fnSym := loader.Sym(s)
|
|
|
|
|
|
|
|
|
|
// Set the PC.
|
|
|
|
|
lsu.AddUint8(0)
|
|
|
|
|
dwarf.Uleb128put(d, lsDwsym, 1+int64(d.arch.PtrSize))
|
|
|
|
|
lsu.AddUint8(dwarf.DW_LNE_set_address)
|
|
|
|
|
addr := lsu.AddAddrPlus(d.arch, fnSym, 0)
|
|
|
|
|
// Make sure the units are sorted.
|
|
|
|
|
if addr < lastAddr {
|
|
|
|
|
d.linkctxt.Errorf(fnSym, "address wasn't increasing %x < %x",
|
|
|
|
|
addr, lastAddr)
|
|
|
|
|
}
|
|
|
|
|
lastAddr = addr
|
|
|
|
|
|
|
|
|
|
// Output the line table.
|
|
|
|
|
// TODO: Now that we have all the debug information in separate
|
|
|
|
|
// symbols, it would make sense to use a rope, and concatenate them all
|
|
|
|
|
// together rather then the append() below. This would allow us to have
|
|
|
|
|
// the compiler emit the DW_LNE_set_address and a rope data structure
|
|
|
|
|
// to concat them all together in the output.
|
|
|
|
|
_, _, _, lines := d.ldr.GetFuncDwarfAuxSyms(fnSym)
|
|
|
|
|
if lines != 0 {
|
|
|
|
|
lsu.AddBytes(d.ldr.Data(lines))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lsu.AddUint8(0) // start extended opcode
|
|
|
|
|
dwarf.Uleb128put(d, lsDwsym, 1)
|
|
|
|
|
lsu.AddUint8(dwarf.DW_LNE_end_sequence)
|
|
|
|
|
|
|
|
|
|
if d.linkctxt.HeadType == objabi.Haix {
|
|
|
|
|
saveDwsectCUSize(".debug_line", unit.Lib.Pkg, uint64(lsu.Size()-unitLengthOffset))
|
|
|
|
|
}
|
|
|
|
|
if isDwarf64(d.linkctxt) {
|
|
|
|
|
lsu.SetUint(d.arch, unitLengthOffset+4, uint64(lsu.Size()-unitstart)) // +4 because of 0xFFFFFFFF
|
|
|
|
|
lsu.SetUint(d.arch, headerLengthOffset, uint64(headerend-headerstart))
|
|
|
|
|
} else {
|
|
|
|
|
lsu.SetUint32(d.arch, unitLengthOffset, uint32(lsu.Size()-unitstart))
|
|
|
|
|
lsu.SetUint32(d.arch, headerLengthOffset, uint32(headerend-headerstart))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Process any R_DWARFFILEREF relocations, since we now know the
|
|
|
|
|
// line table file indices for this compilation unit. Note that
|
|
|
|
|
// this loop visits only subprogram DIEs: if the compiler is
|
|
|
|
|
// changed to generate DW_AT_decl_file attributes for other
|
|
|
|
|
// DIE flavors (ex: variables) then those DIEs would need to
|
|
|
|
|
// be included below.
|
|
|
|
|
missing := make(map[int]interface{})
|
|
|
|
|
for _, f := range unit.FuncDIEs2 {
|
|
|
|
|
fnSym := loader.Sym(f)
|
|
|
|
|
|
|
|
|
|
// Create a symbol updater prior to looking at the relocations
|
|
|
|
|
// on the DWARF subprogram DIE symbol. We need to do this here
|
|
|
|
|
// so that any modifications to the reloc slice will get
|
|
|
|
|
// stored in loader payload for the symbol (as opposed to a
|
|
|
|
|
// temporary slice of relocs read from the object file). Copy
|
|
|
|
|
// back relocations with updated addends.
|
|
|
|
|
fnu := d.ldr.MakeSymbolUpdater(fnSym)
|
|
|
|
|
|
|
|
|
|
relocs := d.ldr.Relocs(fnSym)
|
|
|
|
|
rslice := relocs.ReadAll(nil)
|
|
|
|
|
|
|
|
|
|
for ri := range rslice {
|
|
|
|
|
r := &rslice[ri]
|
|
|
|
|
if r.Type != objabi.R_DWARFFILEREF {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fname, ok := expandedFiles[r.Sym]
|
|
|
|
|
if !ok {
|
|
|
|
|
panic("bad")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
idx, ok := fileNums[fname]
|
|
|
|
|
if ok {
|
|
|
|
|
if int(int32(idx)) != idx {
|
|
|
|
|
d.linkctxt.Errorf(fnSym, "bad R_DWARFFILEREF relocation: file index overflow")
|
|
|
|
|
}
|
|
|
|
|
if r.Size != 4 {
|
|
|
|
|
d.linkctxt.Errorf(fnSym, "bad R_DWARFFILEREF relocation: has size %d, expected 4", r.Size)
|
|
|
|
|
}
|
|
|
|
|
if r.Add != 0 {
|
|
|
|
|
d.linkctxt.Errorf(fnSym, "bad R_DWARFFILEREF relocation: addend not zero")
|
|
|
|
|
}
|
|
|
|
|
if r.Off < 0 || r.Off+4 > int32(len(fnu.Data())) {
|
|
|
|
|
d.linkctxt.Errorf(fnSym, "bad R_DWARFFILEREF relocation offset %d + 4 would write past length %d", r.Off, len(fnu.Data()))
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d.ldr.SetAttrReachable(r.Sym, true)
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(r.Sym, true)
|
|
|
|
|
|
|
|
|
|
r.Add = int64(idx) // record the index in r.Add, we'll apply it in the reloc phase.
|
|
|
|
|
} else {
|
|
|
|
|
sv := d.ldr.SymValue(r.Sym)
|
|
|
|
|
_, found := missing[int(sv)]
|
|
|
|
|
if !found {
|
|
|
|
|
d.linkctxt.Errorf(fnSym, "R_DWARFFILEREF relocation file missing: %s idx %d symVal %d", d.ldr.SymName(r.Sym), r.Sym, sv)
|
|
|
|
|
missing[int(sv)] = nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fnu.WriteRelocs(rslice)
|
|
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2017-10-10 16:19:49 -04:00
|
|
|
// writepcranges generates the DW_AT_ranges table for compilation unit cu.
|
2020-02-14 16:12:51 -05:00
|
|
|
func (d *dwctxt2) writepcranges(unit *sym.CompilationUnit, base loader.Sym, pcs []dwarf.Range, ranges loader.Sym) {
|
|
|
|
|
|
|
|
|
|
rsu := d.ldr.MakeSymbolUpdater(ranges)
|
|
|
|
|
rDwSym := dwSym(ranges)
|
|
|
|
|
|
|
|
|
|
unitLengthOffset := rsu.Size()
|
|
|
|
|
|
|
|
|
|
// Create PC ranges for this CU.
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
if d.linkctxt.HeadType == objabi.Haix {
|
|
|
|
|
addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(rsu.Size()-unitLengthOffset))
|
|
|
|
|
}
|
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-02-14 16:12:51 -05:00
|
|
|
func (d *dwctxt2) writeframes(syms []loader.Sym) []loader.Sym {
|
|
|
|
|
fs := d.ldr.AddExtSym(".debug_frame", 0)
|
|
|
|
|
fsd := dwSym(fs)
|
|
|
|
|
fsu := d.ldr.MakeSymbolUpdater(fs)
|
|
|
|
|
fsu.SetType(sym.SDWARFSECT)
|
|
|
|
|
syms = append(syms, fs)
|
|
|
|
|
isdw64 := isDwarf64(d.linkctxt)
|
|
|
|
|
haslr := haslinkregister(d.linkctxt)
|
|
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fsu.AddBytes(zeros[:pad])
|
|
|
|
|
|
|
|
|
|
var deltaBuf []byte
|
|
|
|
|
pcsp := obj.NewPCIter(uint32(d.arch.MinLC))
|
|
|
|
|
for _, s := range d.linkctxt.Textp2 {
|
|
|
|
|
fn := loader.Sym(s)
|
|
|
|
|
fi := d.ldr.FuncInfo(fn)
|
|
|
|
|
if !fi.Valid() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
fpcsp := fi.Pcsp()
|
|
|
|
|
|
|
|
|
|
// Emit a FDE, Section 6.4.1.
|
|
|
|
|
// First build the section contents into a byte buffer.
|
|
|
|
|
deltaBuf = deltaBuf[:0]
|
|
|
|
|
if haslr && d.ldr.AttrTopFrame(fn) {
|
|
|
|
|
// 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))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for pcsp.Init(fpcsp); !pcsp.Done; pcsp.Next() {
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if haslr && !d.ldr.AttrTopFrame(fn) {
|
|
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
fsu.AddAddrPlus(d.arch, s, 0)
|
|
|
|
|
fsu.AddUintXX(d.arch, uint64(len(d.ldr.Data(fn))), d.arch.PtrSize) // address range
|
|
|
|
|
fsu.AddBytes(deltaBuf)
|
|
|
|
|
|
|
|
|
|
if d.linkctxt.HeadType == objabi.Haix {
|
|
|
|
|
addDwsectCUSize(".debug_frame", d.ldr.SymFile(fn), fdeLength+uint64(lengthFieldSize))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return syms
|
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-02-14 16:12:51 -05:00
|
|
|
// appendSyms appends the syms from 'src' into 'syms' and returns the
|
|
|
|
|
// result. This can go away once we do away with sym.LoaderSym
|
|
|
|
|
// entirely.
|
|
|
|
|
func appendSyms(syms []loader.Sym, src []sym.LoaderSym) []loader.Sym {
|
|
|
|
|
for _, s := range src {
|
|
|
|
|
syms = append(syms, loader.Sym(s))
|
|
|
|
|
}
|
|
|
|
|
return syms
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2020-02-14 16:12:51 -05:00
|
|
|
func (d *dwctxt2) writeinfo(syms []loader.Sym, units []*sym.CompilationUnit, abbrevsym loader.Sym, pubNames, pubTypes *pubWriter2) []loader.Sym {
|
|
|
|
|
|
|
|
|
|
infosec := d.ldr.AddExtSym(".debug_info", 0)
|
|
|
|
|
disu := d.ldr.MakeSymbolUpdater(infosec)
|
|
|
|
|
disu.SetType(sym.SDWARFINFO)
|
|
|
|
|
d.ldr.SetAttrReachable(infosec, true)
|
|
|
|
|
syms = append(syms, infosec)
|
|
|
|
|
|
|
|
|
|
for _, u := range units {
|
|
|
|
|
compunit := u.DWInfo
|
|
|
|
|
s := d.dtolsym(compunit.Sym)
|
|
|
|
|
su := d.ldr.MakeSymbolUpdater(s)
|
|
|
|
|
|
|
|
|
|
if len(u.Textp2) == 0 && u.DWInfo.Child == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pubNames.beginCompUnit(compunit)
|
|
|
|
|
pubTypes.beginCompUnit(compunit)
|
|
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
|
|
|
|
|
// debug_abbrev_offset (*)
|
|
|
|
|
d.addDwarfAddrRef(su, abbrevsym)
|
|
|
|
|
|
|
|
|
|
su.AddUint8(uint8(d.arch.PtrSize)) // address_size
|
|
|
|
|
|
|
|
|
|
ds := dwSym(s)
|
|
|
|
|
dwarf.Uleb128put(d, ds, int64(compunit.Abbrev))
|
|
|
|
|
dwarf.PutAttrs(d, ds, compunit.Abbrev, compunit.Attr)
|
|
|
|
|
|
|
|
|
|
cu := []loader.Sym{s}
|
|
|
|
|
cu = appendSyms(cu, u.AbsFnDIEs2)
|
|
|
|
|
cu = appendSyms(cu, u.FuncDIEs2)
|
|
|
|
|
if u.Consts2 != 0 {
|
|
|
|
|
cu = append(cu, loader.Sym(u.Consts2))
|
|
|
|
|
}
|
|
|
|
|
var cusize int64
|
|
|
|
|
for _, child := range cu {
|
|
|
|
|
cusize += int64(len(d.ldr.Data(child)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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 ispubname(die) {
|
|
|
|
|
pubNames.add(die, cusize)
|
|
|
|
|
}
|
|
|
|
|
if ispubtype(die) {
|
|
|
|
|
pubTypes.add(die, cusize)
|
|
|
|
|
}
|
|
|
|
|
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])))
|
|
|
|
|
}
|
|
|
|
|
for _, child := range cu[l:] {
|
|
|
|
|
cusize += int64(len(d.ldr.Data(child)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
culu := d.ldr.MakeSymbolUpdater(cu[len(cu)-1])
|
|
|
|
|
culu.AddUint8(0) // closes compilation unit DIE
|
|
|
|
|
cusize++
|
|
|
|
|
|
|
|
|
|
// Save size for AIX symbol table.
|
|
|
|
|
if d.linkctxt.HeadType == objabi.Haix {
|
|
|
|
|
saveDwsectCUSize(".debug_info", d.getPkgFromCUSym(s), uint64(cusize))
|
|
|
|
|
}
|
|
|
|
|
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))
|
|
|
|
|
}
|
|
|
|
|
pubNames.endCompUnit(compunit, uint32(cusize)+4)
|
|
|
|
|
pubTypes.endCompUnit(compunit, uint32(cusize)+4)
|
|
|
|
|
syms = append(syms, cu...)
|
|
|
|
|
}
|
|
|
|
|
return syms
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
/*
|
|
|
|
|
* Emit .debug_pubnames/_types. _info must have been written before,
|
|
|
|
|
* because we need die->offs and infoo/infosize;
|
|
|
|
|
*/
|
2020-02-14 16:12:51 -05:00
|
|
|
|
|
|
|
|
type pubWriter2 struct {
|
|
|
|
|
d *dwctxt2
|
|
|
|
|
s loader.Sym
|
|
|
|
|
su *loader.SymbolBuilder
|
|
|
|
|
sname string
|
|
|
|
|
|
|
|
|
|
sectionstart int64
|
|
|
|
|
culengthOff int64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func newPubWriter2(d *dwctxt2, sname string) *pubWriter2 {
|
|
|
|
|
s := d.ldr.AddExtSym(sname, 0)
|
|
|
|
|
u := d.ldr.MakeSymbolUpdater(s)
|
|
|
|
|
u.SetType(sym.SDWARFSECT)
|
|
|
|
|
return &pubWriter2{d: d, s: s, su: u, sname: sname}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pw *pubWriter2) beginCompUnit(compunit *dwarf.DWDie) {
|
|
|
|
|
pw.sectionstart = pw.su.Size()
|
|
|
|
|
|
|
|
|
|
// Write .debug_pubnames/types Header (sec 6.1.1)
|
|
|
|
|
pw.d.createUnitLength(pw.su, 0) // unit_length (*), will be filled in later.
|
|
|
|
|
pw.su.AddUint16(pw.d.arch, 2) // dwarf version (appendix F)
|
|
|
|
|
pw.d.addDwarfAddrRef(pw.su, pw.d.dtolsym(compunit.Sym)) // debug_info_offset (of the Comp unit Header)
|
|
|
|
|
pw.culengthOff = pw.su.Size()
|
|
|
|
|
pw.d.addDwarfAddrField(pw.su, uint64(0)) // debug_info_length, will be filled in later.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pw *pubWriter2) add(die *dwarf.DWDie, offset int64) {
|
|
|
|
|
dwa := getattr(die, dwarf.DW_AT_name)
|
|
|
|
|
name := dwa.Data.(string)
|
|
|
|
|
if pw.d.dtolsym(die.Sym) == 0 {
|
|
|
|
|
fmt.Println("Missing sym for ", name)
|
|
|
|
|
}
|
|
|
|
|
pw.d.addDwarfAddrField(pw.su, uint64(offset))
|
|
|
|
|
pw.su.Addstring(name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (pw *pubWriter2) endCompUnit(compunit *dwarf.DWDie, culength uint32) {
|
|
|
|
|
pw.d.addDwarfAddrField(pw.su, 0) // Null offset
|
|
|
|
|
|
|
|
|
|
// On AIX, save the current size of this compilation unit.
|
|
|
|
|
if pw.d.linkctxt.HeadType == objabi.Haix {
|
|
|
|
|
saveDwsectCUSize(pw.sname, pw.d.getPkgFromCUSym(pw.d.dtolsym(compunit.Sym)), uint64(pw.su.Size()-pw.sectionstart))
|
|
|
|
|
}
|
|
|
|
|
if isDwarf64(pw.d.linkctxt) {
|
|
|
|
|
pw.su.SetUint(pw.d.arch, pw.sectionstart+4, uint64(pw.su.Size()-pw.sectionstart)-12) // exclude the length field.
|
|
|
|
|
pw.su.SetUint(pw.d.arch, pw.culengthOff, uint64(culength))
|
|
|
|
|
} else {
|
|
|
|
|
pw.su.SetUint32(pw.d.arch, pw.sectionstart, uint32(pw.su.Size()-pw.sectionstart)-4) // exclude the length field.
|
|
|
|
|
pw.su.SetUint32(pw.d.arch, pw.culengthOff, culength)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
func ispubname(die *dwarf.DWDie) bool {
|
|
|
|
|
switch die.Abbrev {
|
|
|
|
|
case dwarf.DW_ABRV_FUNCTION, dwarf.DW_ABRV_VARIABLE:
|
|
|
|
|
a := getattr(die, dwarf.DW_AT_external)
|
|
|
|
|
return a != nil && a.Value != 0
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 13:04:41 -04:00
|
|
|
func ispubtype(die *dwarf.DWDie) bool {
|
|
|
|
|
return die.Abbrev >= dwarf.DW_ABRV_NULLTYPE
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func (d *dwctxt2) writegdbscript(syms []loader.Sym) []loader.Sym {
|
2020-02-14 16:12:51 -05:00
|
|
|
// TODO (aix): make it available
|
|
|
|
|
if d.linkctxt.HeadType == objabi.Haix {
|
|
|
|
|
return syms
|
|
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
|
return syms
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if gdbscript != "" {
|
|
|
|
|
gs := d.ldr.AddExtSym(".debug_gdb_scripts", 0)
|
|
|
|
|
u := d.ldr.MakeSymbolUpdater(gs)
|
|
|
|
|
u.SetType(sym.SDWARFSECT)
|
|
|
|
|
|
|
|
|
|
syms = append(syms, gs)
|
|
|
|
|
u.AddUint8(1) // magic 1 byte?
|
|
|
|
|
u.Addstring(gdbscript)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return syms
|
|
|
|
|
|
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
|
|
|
}
|
2017-10-07 13:49:44 -04:00
|
|
|
if *FlagS && ctxt.HeadType != objabi.Hdarwin {
|
2018-04-24 13:05:10 +02:00
|
|
|
return false
|
2016-04-07 14:00:00 -04:00
|
|
|
}
|
2018-03-04 12:59:15 +01:00
|
|
|
if ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hjs {
|
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'.
|
|
|
|
|
func (d *dwctxt2) mkBuiltinType(ctxt *Link, abrv int, tname string) *dwarf.DWDie {
|
|
|
|
|
// create type DIE
|
|
|
|
|
die := d.newdie(&dwtypes, abrv, tname, 0)
|
|
|
|
|
|
|
|
|
|
// Look up type symbol.
|
|
|
|
|
gotype := d.lookupOrDiag("type." + tname)
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
d := newdwctxt2(ctxt, true)
|
|
|
|
|
|
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.
|
|
|
|
|
d.newdie(&dwtypes, dwarf.DW_ABRV_NULLTYPE, "<unspecified>", 0)
|
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)
|
|
|
|
|
d.mkBuiltinType(ctxt, dwarf.DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer")
|
|
|
|
|
die := d.mkBuiltinType(ctxt, dwarf.DW_ABRV_BASETYPE, "uintptr")
|
2016-07-28 13:04:41 -04:00
|
|
|
newattr(die, dwarf.DW_AT_encoding, dwarf.DW_CLS_CONSTANT, dwarf.DW_ATE_unsigned, 0)
|
2019-11-20 10:43:11 -05:00
|
|
|
newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(d.arch.PtrSize), 0)
|
2017-04-18 12:53:25 -07:00
|
|
|
newattr(die, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, objabi.KindUintptr, 0)
|
2020-02-19 16:16:17 -05:00
|
|
|
newattr(die, dwarf.DW_AT_go_runtime_type, dwarf.DW_CLS_ADDRESS, 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{
|
2016-03-14 09:23:04 -07:00
|
|
|
"type.runtime.stringStructDWARF": nil,
|
|
|
|
|
"type.runtime.slice": nil,
|
|
|
|
|
"type.runtime.hmap": nil,
|
|
|
|
|
"type.runtime.bmap": nil,
|
|
|
|
|
"type.runtime.sudog": nil,
|
|
|
|
|
"type.runtime.waitq": nil,
|
|
|
|
|
"type.runtime.hchan": nil,
|
|
|
|
|
}
|
|
|
|
|
|
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{
|
|
|
|
|
"type.runtime._type",
|
|
|
|
|
"type.runtime.arraytype",
|
|
|
|
|
"type.runtime.chantype",
|
|
|
|
|
"type.runtime.functype",
|
|
|
|
|
"type.runtime.maptype",
|
|
|
|
|
"type.runtime.ptrtype",
|
|
|
|
|
"type.runtime.slicetype",
|
|
|
|
|
"type.runtime.structtype",
|
|
|
|
|
"type.runtime.interfacetype",
|
|
|
|
|
"type.runtime.itab",
|
|
|
|
|
"type.runtime.imethod"} {
|
2019-11-20 10:43:11 -05:00
|
|
|
d.defgotype(d.lookupOrDiag(typ))
|
2017-03-18 15:09:40 +01:00
|
|
|
}
|
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)
|
2019-11-20 10:43:11 -05:00
|
|
|
var relocs []loader.Reloc
|
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 {
|
|
|
|
|
unit.Consts2 = sym.LoaderSym(consts)
|
|
|
|
|
d.importInfoSymbol(ctxt, consts)
|
|
|
|
|
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
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
unit.DWInfo = d.newdie(&dwroot, dwarf.DW_ABRV_COMPUNIT, unit.Lib.Pkg, 0)
|
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)
|
|
|
|
|
}
|
2019-08-09 11:36:03 -04:00
|
|
|
producer := "Go cmd/compile " + objabi.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)
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
if len(unit.Textp2) == 0 {
|
2019-08-09 11:36:03 -04:00
|
|
|
unit.DWInfo.Abbrev = dwarf.DW_ABRV_COMPUNIT_TEXTLESS
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Scan all functions in this compilation unit, create DIEs for all
|
|
|
|
|
// referenced types, create the file table for debug_line, find all
|
|
|
|
|
// referenced abstract functions.
|
|
|
|
|
// Collect all debug_range symbols in unit.rangeSyms
|
2019-11-20 10:43:11 -05:00
|
|
|
for _, s := range unit.Textp2 { // textp2 has been dead-code-eliminated already.
|
|
|
|
|
fnSym := loader.Sym(s)
|
|
|
|
|
infosym, _, rangesym, _ := d.ldr.GetFuncDwarfAuxSyms(fnSym)
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(infosym, true)
|
|
|
|
|
d.ldr.SetAttrReachable(infosym, true)
|
2020-02-14 16:12:51 -05:00
|
|
|
|
|
|
|
|
// This is needed only for assembler-generated subprogram DIEs
|
|
|
|
|
// at the moment.
|
|
|
|
|
d.ldr.PatchDWARFName(infosym)
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
unit.FuncDIEs2 = append(unit.FuncDIEs2, sym.LoaderSym(infosym))
|
|
|
|
|
if rangesym != 0 {
|
|
|
|
|
rs := len(d.ldr.Data(rangesym))
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(rangesym, true)
|
|
|
|
|
d.ldr.SetAttrReachable(rangesym, true)
|
2019-08-09 11:36:03 -04:00
|
|
|
if ctxt.HeadType == objabi.Haix {
|
2019-11-20 10:43:11 -05:00
|
|
|
addDwsectCUSize(".debug_ranges", unit.Lib.Pkg, uint64(rs))
|
2019-08-09 11:36:03 -04:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
unit.RangeSyms2 = append(unit.RangeSyms2, sym.LoaderSym(rangesym))
|
2019-08-09 11:36:03 -04:00
|
|
|
}
|
2018-04-24 13:05:10 +02:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
drelocs := d.ldr.Relocs(infosym)
|
|
|
|
|
relocs = drelocs.ReadSyms(relocs)
|
|
|
|
|
for ri := 0; ri < drelocs.Count; ri++ {
|
|
|
|
|
r := &relocs[ri]
|
2019-08-09 11:36:03 -04:00
|
|
|
if r.Type == objabi.R_DWARFSECREF {
|
|
|
|
|
rsym := r.Sym
|
2019-11-20 10:43:11 -05:00
|
|
|
// NB: there should be a better way to do this that doesn't involve materializing the symbol name and doing string prefix+suffix checks.
|
|
|
|
|
rsn := d.ldr.SymName(rsym)
|
|
|
|
|
if strings.HasPrefix(rsn, dwarf.InfoPrefix) && strings.HasSuffix(rsn, dwarf.AbstractFuncSuffix) && !d.ldr.AttrOnList(rsym) {
|
2019-08-09 11:36:03 -04:00
|
|
|
// abstract function
|
2019-11-20 10:43:11 -05:00
|
|
|
d.ldr.SetAttrOnList(rsym, true)
|
|
|
|
|
unit.AbsFnDIEs2 = append(unit.AbsFnDIEs2, sym.LoaderSym(rsym))
|
|
|
|
|
d.importInfoSymbol(ctxt, rsym)
|
|
|
|
|
continue
|
2019-08-09 11:36:03 -04:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
if _, ok := d.rtmap[rsym]; ok {
|
|
|
|
|
// type already generated
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
tn := rsn[len(dwarf.InfoPrefix):]
|
|
|
|
|
ts := d.ldr.Lookup("type."+tn, 0)
|
|
|
|
|
d.defgotype(ts)
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-25 11:52:24 +02:00
|
|
|
// Create DIEs for global variables and the types they use.
|
2019-11-20 10:43:11 -05:00
|
|
|
// FIXME: ideally this should be done in the compiler, since
|
|
|
|
|
// for globals there isn't any abiguity about which package
|
|
|
|
|
// a global belongs to.
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
// Skip things with no type
|
|
|
|
|
if d.ldr.SymGoType(idx) == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sn := d.ldr.SymName(idx)
|
|
|
|
|
if ctxt.LinkMode != LinkExternal && isStaticTemp(sn) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if sn == "" {
|
|
|
|
|
// skip aux symbols
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create DIE for global.
|
|
|
|
|
sv := d.ldr.SymValue(idx)
|
|
|
|
|
gt := d.ldr.SymGoType(idx)
|
|
|
|
|
d.dwarfDefineGlobal(ctxt, idx, sn, sv, gt)
|
|
|
|
|
}
|
2018-09-25 11:52:24 +02:00
|
|
|
|
2019-09-26 08:42:48 -04:00
|
|
|
// Create DIEs for variable types indirectly referenced by function
|
|
|
|
|
// autos (which may not appear directly as param/var DIEs).
|
|
|
|
|
for _, lib := range ctxt.Library {
|
|
|
|
|
for _, unit := range lib.Units {
|
2019-11-20 10:43:11 -05:00
|
|
|
lists := [][]sym.LoaderSym{unit.AbsFnDIEs2, unit.FuncDIEs2}
|
2019-09-26 08:42:48 -04:00
|
|
|
for _, list := range lists {
|
|
|
|
|
for _, s := range list {
|
2019-11-20 10:43:11 -05:00
|
|
|
symIdx := loader.Sym(s)
|
|
|
|
|
srelocs := d.ldr.Relocs(symIdx)
|
|
|
|
|
relocs = srelocs.ReadSyms(relocs)
|
|
|
|
|
for i := 0; i < len(relocs); i++ {
|
|
|
|
|
r := &relocs[i]
|
2019-09-26 08:42:48 -04:00
|
|
|
if r.Type == objabi.R_USETYPE {
|
2019-11-20 10:43:11 -05:00
|
|
|
d.defgotype(r.Sym)
|
2019-09-26 08:42:48 -04: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)
|
|
|
|
|
|
|
|
|
|
// NB: at this stage we have all the DIE objects constructed, but
|
|
|
|
|
// they have loader.Sym attributes and not sym.Symbol attributes.
|
|
|
|
|
// At the point when loadlibfull runs we will need to visit
|
|
|
|
|
// every DIE constructed and convert the symbols.
|
2018-04-24 13:05:10 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// dwarfConvertSymbols is invoked around the time that loader.LoadFull
|
|
|
|
|
// runs (converting all loader.Sym's into sym.Symbols); it walks
|
|
|
|
|
// through dwarf DIE objects and rewrites loader.Sym refs to
|
|
|
|
|
// sym.Symbol there as well. This is obviously a temporary function.
|
|
|
|
|
func dwarfConvertSymbols(ctxt *Link) {
|
2020-03-05 10:58:02 -05:00
|
|
|
if !dwarfEnabled(ctxt) {
|
|
|
|
|
return
|
|
|
|
|
}
|
2020-02-14 16:12:51 -05:00
|
|
|
if *FlagNewDw2 {
|
|
|
|
|
// don't convert since we're running phase 2 with loader
|
|
|
|
|
return
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
convdies := make(map[*dwarf.DWDie]bool)
|
|
|
|
|
for _, lib := range ctxt.Library {
|
|
|
|
|
for _, unit := range lib.Units {
|
|
|
|
|
convertSymbolsInDIE(ctxt, unit.DWInfo, convdies)
|
|
|
|
|
}
|
2018-04-24 13:05:10 +02:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
convertSymbolsInDIE(ctxt, &dwtypes, convdies)
|
2018-04-24 13:05:10 +02:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// Convert over the unit function DIE and abstract function DIE lists.
|
|
|
|
|
for _, lib := range ctxt.Library {
|
|
|
|
|
for _, unit := range lib.Units {
|
|
|
|
|
for _, fd := range unit.FuncDIEs2 {
|
|
|
|
|
ds := ctxt.loader.Syms[fd]
|
|
|
|
|
if ds == nil {
|
|
|
|
|
panic("bad")
|
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
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
unit.FuncDIEs = append(unit.FuncDIEs, ds)
|
|
|
|
|
}
|
|
|
|
|
for _, fd := range unit.RangeSyms2 {
|
|
|
|
|
ds := ctxt.loader.Syms[fd]
|
|
|
|
|
if ds == nil {
|
|
|
|
|
panic("bad")
|
|
|
|
|
}
|
|
|
|
|
unit.RangeSyms = append(unit.RangeSyms, ds)
|
|
|
|
|
}
|
|
|
|
|
for _, fd := range unit.AbsFnDIEs2 {
|
|
|
|
|
ds := ctxt.loader.Syms[fd]
|
|
|
|
|
if ds == nil {
|
|
|
|
|
panic("bad")
|
|
|
|
|
}
|
|
|
|
|
unit.AbsFnDIEs = append(unit.AbsFnDIEs, ds)
|
|
|
|
|
}
|
|
|
|
|
if unit.Consts2 != 0 {
|
|
|
|
|
ds := ctxt.loader.Syms[unit.Consts2]
|
|
|
|
|
if ds == nil {
|
|
|
|
|
panic("bad")
|
|
|
|
|
}
|
|
|
|
|
unit.Consts = ds
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
}
|
cmd/link: compress DWARF sections in ELF binaries
Forked from CL 111895.
The trickiest part of this is that the binary layout code (blk,
elfshbits, and various other things) assumes a constant offset between
symbols' and sections' file locations and their virtual addresses.
Compression, of course, breaks this constant offset. But we need to
assign virtual addresses to everything before compression in order to
resolve relocations before compression. As a result, compression needs
to re-compute the "address" of the DWARF sections and symbols based on
their compressed size. Luckily, these are at the end of the file, so
this doesn't perturb any other sections or symbols. (And there is, of
course, a surprising amount of code that assumes the DWARF segment
comes last, so what's one more place?)
Relevant benchmarks:
name old time/op new time/op delta
StdCmd 10.3s ± 2% 10.8s ± 1% +5.43% (p=0.000 n=30+30)
name old text-bytes new text-bytes delta
HelloSize 746kB ± 0% 746kB ± 0% ~ (all equal)
CmdGoSize 8.41MB ± 0% 8.41MB ± 0% ~ (all equal)
[Geo mean] 2.50MB 2.50MB +0.00%
name old data-bytes new data-bytes delta
HelloSize 10.6kB ± 0% 10.6kB ± 0% ~ (all equal)
CmdGoSize 252kB ± 0% 252kB ± 0% ~ (all equal)
[Geo mean] 51.5kB 51.5kB +0.00%
name old bss-bytes new bss-bytes delta
HelloSize 125kB ± 0% 125kB ± 0% ~ (all equal)
CmdGoSize 145kB ± 0% 145kB ± 0% ~ (all equal)
[Geo mean] 135kB 135kB +0.00%
name old exe-bytes new exe-bytes delta
HelloSize 1.60MB ± 0% 1.05MB ± 0% -34.39% (p=0.000 n=30+30)
CmdGoSize 16.5MB ± 0% 11.3MB ± 0% -31.76% (p=0.000 n=30+30)
[Geo mean] 5.14MB 3.44MB -33.08%
Fixes #11799.
Updates #6853.
Change-Id: I64197afe4c01a237523a943088051ee056331c6f
Reviewed-on: https://go-review.googlesource.com/118276
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2018-05-05 21:49:40 -04:00
|
|
|
}
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
func convertSymbolsInDIE(ctxt *Link, die *dwarf.DWDie, convdies map[*dwarf.DWDie]bool) {
|
|
|
|
|
if die == nil {
|
2015-02-27 22:57:28 -05:00
|
|
|
return
|
|
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
if convdies[die] {
|
2016-03-14 09:23:04 -07:00
|
|
|
return
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
convdies[die] = true
|
|
|
|
|
if die.Sym != nil {
|
2020-02-19 16:16:17 -05:00
|
|
|
ds, ok := die.Sym.(dwSym)
|
2019-11-20 10:43:11 -05:00
|
|
|
if !ok {
|
|
|
|
|
panic("bad die sym field")
|
cmd/link: compress DWARF sections in ELF binaries
Forked from CL 111895.
The trickiest part of this is that the binary layout code (blk,
elfshbits, and various other things) assumes a constant offset between
symbols' and sections' file locations and their virtual addresses.
Compression, of course, breaks this constant offset. But we need to
assign virtual addresses to everything before compression in order to
resolve relocations before compression. As a result, compression needs
to re-compute the "address" of the DWARF sections and symbols based on
their compressed size. Luckily, these are at the end of the file, so
this doesn't perturb any other sections or symbols. (And there is, of
course, a surprising amount of code that assumes the DWARF segment
comes last, so what's one more place?)
Relevant benchmarks:
name old time/op new time/op delta
StdCmd 10.3s ± 2% 10.8s ± 1% +5.43% (p=0.000 n=30+30)
name old text-bytes new text-bytes delta
HelloSize 746kB ± 0% 746kB ± 0% ~ (all equal)
CmdGoSize 8.41MB ± 0% 8.41MB ± 0% ~ (all equal)
[Geo mean] 2.50MB 2.50MB +0.00%
name old data-bytes new data-bytes delta
HelloSize 10.6kB ± 0% 10.6kB ± 0% ~ (all equal)
CmdGoSize 252kB ± 0% 252kB ± 0% ~ (all equal)
[Geo mean] 51.5kB 51.5kB +0.00%
name old bss-bytes new bss-bytes delta
HelloSize 125kB ± 0% 125kB ± 0% ~ (all equal)
CmdGoSize 145kB ± 0% 145kB ± 0% ~ (all equal)
[Geo mean] 135kB 135kB +0.00%
name old exe-bytes new exe-bytes delta
HelloSize 1.60MB ± 0% 1.05MB ± 0% -34.39% (p=0.000 n=30+30)
CmdGoSize 16.5MB ± 0% 11.3MB ± 0% -31.76% (p=0.000 n=30+30)
[Geo mean] 5.14MB 3.44MB -33.08%
Fixes #11799.
Updates #6853.
Change-Id: I64197afe4c01a237523a943088051ee056331c6f
Reviewed-on: https://go-review.googlesource.com/118276
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2018-05-05 21:49:40 -04:00
|
|
|
}
|
2020-02-19 16:16:17 -05:00
|
|
|
symIdx := loader.Sym(ds)
|
|
|
|
|
if symIdx == 0 {
|
2019-11-20 10:43:11 -05:00
|
|
|
panic("zero loader sym for die")
|
cmd/link: compress DWARF sections in ELF binaries
Forked from CL 111895.
The trickiest part of this is that the binary layout code (blk,
elfshbits, and various other things) assumes a constant offset between
symbols' and sections' file locations and their virtual addresses.
Compression, of course, breaks this constant offset. But we need to
assign virtual addresses to everything before compression in order to
resolve relocations before compression. As a result, compression needs
to re-compute the "address" of the DWARF sections and symbols based on
their compressed size. Luckily, these are at the end of the file, so
this doesn't perturb any other sections or symbols. (And there is, of
course, a surprising amount of code that assumes the DWARF segment
comes last, so what's one more place?)
Relevant benchmarks:
name old time/op new time/op delta
StdCmd 10.3s ± 2% 10.8s ± 1% +5.43% (p=0.000 n=30+30)
name old text-bytes new text-bytes delta
HelloSize 746kB ± 0% 746kB ± 0% ~ (all equal)
CmdGoSize 8.41MB ± 0% 8.41MB ± 0% ~ (all equal)
[Geo mean] 2.50MB 2.50MB +0.00%
name old data-bytes new data-bytes delta
HelloSize 10.6kB ± 0% 10.6kB ± 0% ~ (all equal)
CmdGoSize 252kB ± 0% 252kB ± 0% ~ (all equal)
[Geo mean] 51.5kB 51.5kB +0.00%
name old bss-bytes new bss-bytes delta
HelloSize 125kB ± 0% 125kB ± 0% ~ (all equal)
CmdGoSize 145kB ± 0% 145kB ± 0% ~ (all equal)
[Geo mean] 135kB 135kB +0.00%
name old exe-bytes new exe-bytes delta
HelloSize 1.60MB ± 0% 1.05MB ± 0% -34.39% (p=0.000 n=30+30)
CmdGoSize 16.5MB ± 0% 11.3MB ± 0% -31.76% (p=0.000 n=30+30)
[Geo mean] 5.14MB 3.44MB -33.08%
Fixes #11799.
Updates #6853.
Change-Id: I64197afe4c01a237523a943088051ee056331c6f
Reviewed-on: https://go-review.googlesource.com/118276
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2018-05-05 21:49:40 -04:00
|
|
|
}
|
2020-02-19 16:16:17 -05:00
|
|
|
die.Sym = ctxt.loader.Syms[symIdx]
|
2019-11-20 10:43:11 -05:00
|
|
|
}
|
|
|
|
|
for a := die.Attr; a != nil; a = a.Link {
|
|
|
|
|
if attrSym, ok := a.Data.(dwSym); ok {
|
2020-02-19 16:16:17 -05:00
|
|
|
a.Data = ctxt.loader.Syms[loader.Sym(attrSym)]
|
2018-06-19 15:39:17 -04:00
|
|
|
}
|
cmd/link: compress DWARF sections in ELF binaries
Forked from CL 111895.
The trickiest part of this is that the binary layout code (blk,
elfshbits, and various other things) assumes a constant offset between
symbols' and sections' file locations and their virtual addresses.
Compression, of course, breaks this constant offset. But we need to
assign virtual addresses to everything before compression in order to
resolve relocations before compression. As a result, compression needs
to re-compute the "address" of the DWARF sections and symbols based on
their compressed size. Luckily, these are at the end of the file, so
this doesn't perturb any other sections or symbols. (And there is, of
course, a surprising amount of code that assumes the DWARF segment
comes last, so what's one more place?)
Relevant benchmarks:
name old time/op new time/op delta
StdCmd 10.3s ± 2% 10.8s ± 1% +5.43% (p=0.000 n=30+30)
name old text-bytes new text-bytes delta
HelloSize 746kB ± 0% 746kB ± 0% ~ (all equal)
CmdGoSize 8.41MB ± 0% 8.41MB ± 0% ~ (all equal)
[Geo mean] 2.50MB 2.50MB +0.00%
name old data-bytes new data-bytes delta
HelloSize 10.6kB ± 0% 10.6kB ± 0% ~ (all equal)
CmdGoSize 252kB ± 0% 252kB ± 0% ~ (all equal)
[Geo mean] 51.5kB 51.5kB +0.00%
name old bss-bytes new bss-bytes delta
HelloSize 125kB ± 0% 125kB ± 0% ~ (all equal)
CmdGoSize 145kB ± 0% 145kB ± 0% ~ (all equal)
[Geo mean] 135kB 135kB +0.00%
name old exe-bytes new exe-bytes delta
HelloSize 1.60MB ± 0% 1.05MB ± 0% -34.39% (p=0.000 n=30+30)
CmdGoSize 16.5MB ± 0% 11.3MB ± 0% -31.76% (p=0.000 n=30+30)
[Geo mean] 5.14MB 3.44MB -33.08%
Fixes #11799.
Updates #6853.
Change-Id: I64197afe4c01a237523a943088051ee056331c6f
Reviewed-on: https://go-review.googlesource.com/118276
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2018-05-05 21:49:40 -04:00
|
|
|
}
|
2019-11-20 10:43:11 -05:00
|
|
|
convertSymbolsInDIE(ctxt, die.Child, convdies)
|
|
|
|
|
convertSymbolsInDIE(ctxt, die.Link, convdies)
|
cmd/link: compress DWARF sections in ELF binaries
Forked from CL 111895.
The trickiest part of this is that the binary layout code (blk,
elfshbits, and various other things) assumes a constant offset between
symbols' and sections' file locations and their virtual addresses.
Compression, of course, breaks this constant offset. But we need to
assign virtual addresses to everything before compression in order to
resolve relocations before compression. As a result, compression needs
to re-compute the "address" of the DWARF sections and symbols based on
their compressed size. Luckily, these are at the end of the file, so
this doesn't perturb any other sections or symbols. (And there is, of
course, a surprising amount of code that assumes the DWARF segment
comes last, so what's one more place?)
Relevant benchmarks:
name old time/op new time/op delta
StdCmd 10.3s ± 2% 10.8s ± 1% +5.43% (p=0.000 n=30+30)
name old text-bytes new text-bytes delta
HelloSize 746kB ± 0% 746kB ± 0% ~ (all equal)
CmdGoSize 8.41MB ± 0% 8.41MB ± 0% ~ (all equal)
[Geo mean] 2.50MB 2.50MB +0.00%
name old data-bytes new data-bytes delta
HelloSize 10.6kB ± 0% 10.6kB ± 0% ~ (all equal)
CmdGoSize 252kB ± 0% 252kB ± 0% ~ (all equal)
[Geo mean] 51.5kB 51.5kB +0.00%
name old bss-bytes new bss-bytes delta
HelloSize 125kB ± 0% 125kB ± 0% ~ (all equal)
CmdGoSize 145kB ± 0% 145kB ± 0% ~ (all equal)
[Geo mean] 135kB 135kB +0.00%
name old exe-bytes new exe-bytes delta
HelloSize 1.60MB ± 0% 1.05MB ± 0% -34.39% (p=0.000 n=30+30)
CmdGoSize 16.5MB ± 0% 11.3MB ± 0% -31.76% (p=0.000 n=30+30)
[Geo mean] 5.14MB 3.44MB -33.08%
Fixes #11799.
Updates #6853.
Change-Id: I64197afe4c01a237523a943088051ee056331c6f
Reviewed-on: https://go-review.googlesource.com/118276
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2018-05-05 21:49:40 -04:00
|
|
|
}
|
2018-04-24 13:05:10 +02:00
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// dwarfGenerateDebugSyms constructs debug_line, debug_frame, debug_loc,
|
|
|
|
|
// debug_pubnames and debug_pubtypes. It also writes out the debug_info
|
|
|
|
|
// section using symbols generated in dwarfGenerateDebugInfo2.
|
2020-02-14 16:12:51 -05:00
|
|
|
func dwarfGenerateDebugSyms2(ctxt *Link) {
|
2019-11-20 10:43:11 -05:00
|
|
|
if !dwarfEnabled(ctxt) {
|
|
|
|
|
return
|
2018-09-25 11:52:24 +02:00
|
|
|
}
|
2020-02-14 16:12:51 -05:00
|
|
|
d := &dwctxt2{
|
|
|
|
|
linkctxt: ctxt,
|
|
|
|
|
ldr: ctxt.loader,
|
|
|
|
|
arch: ctxt.Arch,
|
|
|
|
|
}
|
|
|
|
|
d.dwarfGenerateDebugSyms()
|
2018-04-24 13:05:10 +02:00
|
|
|
}
|
2018-09-28 16:44:30 +02:00
|
|
|
|
2020-02-14 16:12:51 -05:00
|
|
|
func (d *dwctxt2) dwarfGenerateDebugSyms() {
|
|
|
|
|
|
|
|
|
|
// Hack: because the "wavefront" hasn't been pushed all the way
|
|
|
|
|
// up to dodata(), there will have been changes made to the sym.Symbol's
|
|
|
|
|
// that are not yet reflected in the loader. Call a temporary
|
|
|
|
|
// loader routine that copies any changes back.
|
|
|
|
|
// WARNING: changing a symbol's content will usually require
|
|
|
|
|
// calling the loader cloneToExternal method, meaning that there
|
|
|
|
|
// can be an increase in memory, so this is likely to mess up any
|
|
|
|
|
// benchmarking runs.
|
|
|
|
|
d.ldr.PropagateSymbolChangesBackToLoader()
|
|
|
|
|
|
|
|
|
|
abbrev := d.writeabbrev()
|
|
|
|
|
syms := []loader.Sym{abbrev}
|
|
|
|
|
|
|
|
|
|
d.calcCompUnitRanges()
|
|
|
|
|
sort.Sort(compilationUnitByStartPC(d.linkctxt.compUnits))
|
|
|
|
|
|
|
|
|
|
// Create .debug_line and .debug_ranges section symbols
|
|
|
|
|
debugLine := d.ldr.AddExtSym(".debug_line", 0)
|
|
|
|
|
dlu := d.ldr.MakeSymbolUpdater(debugLine)
|
|
|
|
|
dlu.SetType(sym.SDWARFSECT)
|
|
|
|
|
d.ldr.SetAttrReachable(debugLine, true)
|
|
|
|
|
syms = append(syms, debugLine)
|
|
|
|
|
|
|
|
|
|
debugRanges := d.ldr.AddExtSym(".debug_ranges", 0)
|
|
|
|
|
dru := d.ldr.MakeSymbolUpdater(debugRanges)
|
|
|
|
|
dru.SetType(sym.SDWARFRANGE)
|
|
|
|
|
d.ldr.SetAttrReachable(debugRanges, true)
|
|
|
|
|
|
|
|
|
|
// Write per-package line and range tables and start their CU DIEs.
|
|
|
|
|
for _, u := range d.linkctxt.compUnits {
|
|
|
|
|
reversetree(&u.DWInfo.Child)
|
|
|
|
|
if u.DWInfo.Abbrev == dwarf.DW_ABRV_COMPUNIT_TEXTLESS {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
d.writelines(u, debugLine)
|
|
|
|
|
base := loader.Sym(u.Textp2[0])
|
|
|
|
|
d.writepcranges(u, base, u.PCs, debugRanges)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
reversetree(&dwtypes.Child)
|
|
|
|
|
movetomodule(d.linkctxt, &dwtypes)
|
|
|
|
|
|
|
|
|
|
pubNames := newPubWriter2(d, ".debug_pubnames")
|
|
|
|
|
pubTypes := newPubWriter2(d, ".debug_pubtypes")
|
|
|
|
|
|
|
|
|
|
// Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT
|
|
|
|
|
infosyms := d.writeinfo(nil, d.linkctxt.compUnits, abbrev, pubNames, pubTypes)
|
|
|
|
|
|
|
|
|
|
syms = d.writeframes(syms)
|
|
|
|
|
syms = append(syms, pubNames.s, pubTypes.s)
|
|
|
|
|
syms = d.writegdbscript(syms)
|
|
|
|
|
// We are now done writing SDWARFSECT symbols, so we can write
|
|
|
|
|
// other SDWARF* symbols.
|
|
|
|
|
syms = append(syms, infosyms...)
|
|
|
|
|
syms = d.collectlocs(syms, d.linkctxt.compUnits)
|
|
|
|
|
syms = append(syms, debugRanges)
|
|
|
|
|
for _, unit := range d.linkctxt.compUnits {
|
|
|
|
|
for _, s := range unit.RangeSyms2 {
|
|
|
|
|
syms = append(syms, loader.Sym(s))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dwarfp2 = syms
|
|
|
|
|
dwarfp = d.ldr.PropagateLoaderChangesToSymbols(dwarfp2, d.linkctxt.Syms)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *dwctxt2) collectlocs(syms []loader.Sym, units []*sym.CompilationUnit) []loader.Sym {
|
|
|
|
|
empty := true
|
|
|
|
|
rslice := []loader.Reloc{}
|
|
|
|
|
for _, u := range units {
|
|
|
|
|
for _, fn := range u.FuncDIEs2 {
|
|
|
|
|
relocs := d.ldr.Relocs(loader.Sym(fn))
|
|
|
|
|
rslice := relocs.ReadSyms(rslice)
|
|
|
|
|
for i := range rslice {
|
|
|
|
|
reloc := &rslice[i]
|
|
|
|
|
if reloc.Type != objabi.R_DWARFSECREF {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
sn := d.ldr.SymName(reloc.Sym)
|
|
|
|
|
if strings.HasPrefix(sn, dwarf.LocPrefix) {
|
|
|
|
|
d.ldr.SetAttrReachable(reloc.Sym, true)
|
|
|
|
|
d.ldr.SetAttrNotInSymbolTable(reloc.Sym, true)
|
|
|
|
|
syms = append(syms, reloc.Sym)
|
|
|
|
|
empty = false
|
|
|
|
|
// One location list entry per function, but many relocations to it. Don't duplicate.
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Don't emit .debug_loc if it's empty -- it makes the ARM linker mad.
|
|
|
|
|
if !empty {
|
|
|
|
|
locsym := d.ldr.AddExtSym(".debug_loc", 0)
|
|
|
|
|
u := d.ldr.MakeSymbolUpdater(locsym)
|
|
|
|
|
u.SetType(sym.SDWARFLOC)
|
|
|
|
|
d.ldr.SetAttrReachable(locsym, true)
|
|
|
|
|
syms = append(syms, locsym)
|
|
|
|
|
}
|
|
|
|
|
return syms
|
2018-09-28 16:44:30 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
/*
|
|
|
|
|
* Elf.
|
|
|
|
|
*/
|
|
|
|
|
func (d *dwctxt2) dwarfaddshstrings(ctxt *Link, shstrtab loader.Sym) {
|
|
|
|
|
panic("not yet implemented")
|
2018-09-28 16:44:30 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// Add section symbols for DWARF debug info. This is called before
|
|
|
|
|
// dwarfaddelfheaders.
|
|
|
|
|
func (d *dwctxt2) dwarfaddelfsectionsyms(ctxt *Link) {
|
|
|
|
|
panic("not yet implemented")
|
2019-02-20 16:29:00 +01:00
|
|
|
}
|
|
|
|
|
|
2019-11-20 10:43:11 -05:00
|
|
|
// 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 (d *dwctxt2) dwarfcompress(ctxt *Link) {
|
|
|
|
|
panic("not yet implemented")
|
2018-09-28 16:44:30 +02: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.
|
|
|
|
|
func (d *dwctxt2) getPkgFromCUSym(s loader.Sym) string {
|
|
|
|
|
return strings.TrimPrefix(d.ldr.SymName(s), dwarf.InfoPrefix+".pkg.")
|
|
|
|
|
}
|