2016-03-01 22:57:46 +00:00
// Copyright 2013 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.
package ld
import (
"cmd/internal/obj"
"log"
2015-12-29 10:16:40 -05:00
"os"
"path/filepath"
2015-02-27 22:57:28 -05:00
)
// iteration over encoded pcdata tables.
func getvarint ( pp * [ ] byte ) uint32 {
2015-03-02 12:35:15 -05:00
v := uint32 ( 0 )
p := * pp
for shift := 0 ; ; shift += 7 {
2015-02-27 22:57:28 -05:00
v |= uint32 ( p [ 0 ] & 0x7F ) << uint ( shift )
tmp4 := p
p = p [ 1 : ]
if tmp4 [ 0 ] & 0x80 == 0 {
break
}
}
* pp = p
return v
}
func pciternext ( it * Pciter ) {
it . pc = it . nextpc
if it . done != 0 {
return
}
if - cap ( it . p ) >= - cap ( it . d . P [ len ( it . d . P ) : ] ) {
it . done = 1
return
}
// value delta
2015-03-02 12:35:15 -05:00
v := getvarint ( & it . p )
2015-02-27 22:57:28 -05:00
if v == 0 && it . start == 0 {
it . done = 1
return
}
it . start = 0
2015-03-02 12:35:15 -05:00
dv := int32 ( v >> 1 ) ^ ( int32 ( v << 31 ) >> 31 )
2015-02-27 22:57:28 -05:00
it . value += dv
// pc delta
v = getvarint ( & it . p )
it . nextpc = it . pc + v * it . pcscale
}
func pciterinit ( ctxt * Link , it * Pciter , d * Pcdata ) {
it . d = * d
it . p = it . d . P
it . pc = 0
it . nextpc = 0
it . value = - 1
it . start = 1
it . done = 0
2016-04-06 12:01:40 -07:00
it . pcscale = uint32 ( ctxt . Arch . MinLC )
2015-02-27 22:57:28 -05:00
pciternext ( it )
}
func addvarint ( d * Pcdata , val uint32 ) {
2015-03-02 12:35:15 -05:00
n := int32 ( 0 )
for v := val ; v >= 0x80 ; v >>= 7 {
2015-02-27 22:57:28 -05:00
n ++
}
n ++
old := len ( d . P )
for cap ( d . P ) < len ( d . P ) + int ( n ) {
d . P = append ( d . P [ : cap ( d . P ) ] , 0 )
}
d . P = d . P [ : old + int ( n ) ]
2015-03-02 12:35:15 -05:00
p := d . P [ old : ]
var v uint32
2015-02-27 22:57:28 -05:00
for v = val ; v >= 0x80 ; v >>= 7 {
p [ 0 ] = byte ( v | 0x80 )
p = p [ 1 : ]
}
p [ 0 ] = byte ( v )
}
2016-08-19 22:40:38 -04:00
func addpctab ( ctxt * Link , ftab * Symbol , off int32 , d * Pcdata ) int32 {
2015-06-28 22:26:35 -04:00
var start int32
if len ( d . P ) > 0 {
start = int32 ( len ( ftab . P ) )
2016-09-20 15:31:26 +12:00
Addbytes ( ftab , d . P )
2015-06-28 22:26:35 -04:00
}
2016-08-19 22:40:38 -04:00
return int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , uint32 ( start ) ) )
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
func ftabaddstring ( ctxt * Link , ftab * Symbol , s string ) int32 {
2015-03-02 12:35:15 -05:00
n := int32 ( len ( s ) ) + 1
start := int32 ( len ( ftab . P ) )
2016-09-20 15:31:26 +12:00
Symgrow ( ftab , int64 ( start ) + int64 ( n ) + 1 )
2015-02-27 22:57:28 -05:00
copy ( ftab . P [ start : ] , s )
return start
}
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
// numberfile assigns a file number to the file if it hasn't been assigned already.
func numberfile ( ctxt * Link , file * Symbol ) {
if file . Type != obj . SFILEPATH {
ctxt . Filesyms = append ( ctxt . Filesyms , file )
file . Value = int64 ( len ( ctxt . Filesyms ) )
file . Type = obj . SFILEPATH
2017-02-17 16:20:52 -05:00
path := file . Name [ len ( obj . FileSymPrefix ) : ]
file . Name = expandGoroot ( path )
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
}
}
2016-08-19 11:35:54 -04:00
func renumberfiles ( ctxt * Link , files [ ] * Symbol , d * Pcdata ) {
var f * Symbol
2015-02-27 22:57:28 -05:00
// Give files numbers.
2015-03-02 12:35:15 -05:00
for i := 0 ; i < len ( files ) ; i ++ {
2015-02-27 22:57:28 -05:00
f = files [ i ]
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
numberfile ( ctxt , f )
2015-02-27 22:57:28 -05:00
}
2015-03-02 12:35:15 -05:00
newval := int32 ( - 1 )
2015-03-02 14:22:05 -05:00
var out Pcdata
2015-03-02 12:35:15 -05:00
var it Pciter
2015-02-27 22:57:28 -05:00
for pciterinit ( ctxt , & it , d ) ; it . done == 0 ; pciternext ( & it ) {
// value delta
2016-04-20 14:22:20 -04:00
oldval := it . value
2015-02-27 22:57:28 -05:00
2016-04-20 14:22:20 -04:00
var val int32
2015-02-27 22:57:28 -05:00
if oldval == - 1 {
val = - 1
} else {
if oldval < 0 || oldval >= int32 ( len ( files ) ) {
log . Fatalf ( "bad pcdata %d" , oldval )
}
val = int32 ( files [ oldval ] . Value )
}
2016-04-20 14:22:20 -04:00
dv := val - newval
2015-02-27 22:57:28 -05:00
newval = val
2016-04-20 14:22:20 -04:00
v := ( uint32 ( dv ) << 1 ) ^ uint32 ( dv >> 31 )
2015-02-27 22:57:28 -05:00
addvarint ( & out , v )
// pc delta
addvarint ( & out , ( it . nextpc - it . pc ) / it . pcscale )
}
// terminating value delta
addvarint ( & out , 0 )
* d = out
}
2016-12-10 13:30:13 -05:00
// onlycsymbol reports whether this is a cgo symbol provided by the
// runtime and only used from C code.
func onlycsymbol ( s * Symbol ) bool {
switch s . Name {
case "_cgo_topofstack" , "_cgo_panic" , "crosscall2" :
return true
}
return false
}
2016-08-19 11:35:54 -04:00
func container ( s * Symbol ) int {
2016-12-10 13:30:13 -05:00
if s == nil {
return 0
}
2017-01-12 17:35:53 -05:00
if Buildmode == BuildmodePlugin && Headtype == obj . Hdarwin && onlycsymbol ( s ) {
2016-12-10 13:30:13 -05:00
return 1
}
2015-02-27 22:57:28 -05:00
// We want to generate func table entries only for the "lowest level" symbols,
// not containers of subsymbols.
2016-12-10 13:30:13 -05:00
if s . Type & obj . SCONTAINER != 0 {
2015-02-27 22:57:28 -05:00
return 1
}
return 0
}
// pclntab initializes the pclntab symbol with
// runtime function and file name information.
2016-08-22 10:33:13 -04:00
var pclntabZpcln FuncInfo
2015-02-27 22:57:28 -05:00
2015-04-07 12:55:02 +12:00
// These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
2015-03-16 11:53:08 +13:00
var pclntabNfunc int32
var pclntabFiletabOffset int32
var pclntabPclntabOffset int32
2016-08-19 11:35:54 -04:00
var pclntabFirstFunc * Symbol
var pclntabLastFunc * Symbol
2015-03-16 11:53:08 +13:00
2016-08-19 22:40:38 -04:00
func ( ctxt * Link ) pclntab ( ) {
2016-08-22 10:33:13 -04:00
funcdataBytes := int64 ( 0 )
cmd/link: use ctxt.{Lookup,ROLookup} in favour of function versions of same
Done with two eg templates:
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linklookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.Lookup(name, v)
}
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linkrlookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.ROLookup(name, v)
}
Change-Id: I00647dbf62294557bd24c29ad1f108fc786335f1
Reviewed-on: https://go-review.googlesource.com/29343
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-09-20 15:06:08 +12:00
ftab := ctxt . Syms . Lookup ( "runtime.pclntab" , 0 )
2015-04-19 19:33:58 -07:00
ftab . Type = obj . SPCLNTAB
2016-03-02 07:59:49 -05:00
ftab . Attr |= AttrReachable
2015-02-27 22:57:28 -05:00
// See golang.org/s/go12symtab for the format. Briefly:
// 8-byte header
// nfunc [thearch.ptrsize bytes]
// function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
// end PC [thearch.ptrsize bytes]
// offset to file table [4 bytes]
2015-03-02 12:35:15 -05:00
nfunc := int32 ( 0 )
2015-02-27 22:57:28 -05:00
2015-06-27 12:57:06 -07:00
// Find container symbols, mark them with SCONTAINER
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
2016-04-19 14:02:21 -04:00
if s . Outer != nil {
s . Outer . Type |= obj . SCONTAINER
2015-06-27 12:57:06 -07:00
}
}
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
2016-04-19 14:02:21 -04:00
if container ( s ) == 0 {
2015-02-27 22:57:28 -05:00
nfunc ++
}
}
2015-03-16 11:53:08 +13:00
pclntabNfunc = nfunc
2016-09-20 15:31:26 +12:00
Symgrow ( ftab , 8 + int64 ( SysArch . PtrSize ) + int64 ( nfunc ) * 2 * int64 ( SysArch . PtrSize ) + int64 ( SysArch . PtrSize ) + 4 )
2016-08-19 22:40:38 -04:00
setuint32 ( ctxt , ftab , 0 , 0xfffffffb )
setuint8 ( ctxt , ftab , 6 , uint8 ( SysArch . MinLC ) )
setuint8 ( ctxt , ftab , 7 , uint8 ( SysArch . PtrSize ) )
setuintxx ( ctxt , ftab , 8 , uint64 ( nfunc ) , int64 ( SysArch . PtrSize ) )
2016-04-06 12:01:40 -07:00
pclntabPclntabOffset = int32 ( 8 + SysArch . PtrSize )
2015-02-27 22:57:28 -05:00
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
funcnameoff := make ( map [ string ] int32 )
nameToOffset := func ( name string ) int32 {
nameoff , ok := funcnameoff [ name ]
if ! ok {
nameoff = ftabaddstring ( ctxt , ftab , name )
funcnameoff [ name ] = nameoff
}
return nameoff
}
2015-02-27 22:57:28 -05:00
nfunc = 0
2016-08-19 11:35:54 -04:00
var last * Symbol
2016-09-17 10:01:17 -04:00
for _ , s := range ctxt . Textp {
last = s
if container ( s ) != 0 {
2015-02-27 22:57:28 -05:00
continue
}
2016-09-17 10:01:17 -04:00
pcln := s . FuncInfo
2015-02-27 22:57:28 -05:00
if pcln == nil {
2016-08-22 10:33:13 -04:00
pcln = & pclntabZpcln
2015-02-27 22:57:28 -05:00
}
2015-03-16 11:53:08 +13:00
if pclntabFirstFunc == nil {
2016-09-17 10:01:17 -04:00
pclntabFirstFunc = s
2015-03-16 11:53:08 +13:00
}
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
if len ( pcln . InlTree ) > 0 {
if len ( pcln . Pcdata ) <= obj . PCDATA_InlTreeIndex {
// Create inlining pcdata table.
pcdata := make ( [ ] Pcdata , obj . PCDATA_InlTreeIndex + 1 )
copy ( pcdata , pcln . Pcdata )
pcln . Pcdata = pcdata
}
if len ( pcln . Funcdataoff ) <= obj . FUNCDATA_InlTree {
// Create inline tree funcdata.
funcdata := make ( [ ] * Symbol , obj . FUNCDATA_InlTree + 1 )
funcdataoff := make ( [ ] int64 , obj . FUNCDATA_InlTree + 1 )
copy ( funcdata , pcln . Funcdata )
copy ( funcdataoff , pcln . Funcdataoff )
pcln . Funcdata = funcdata
pcln . Funcdataoff = funcdataoff
}
}
2016-04-20 14:22:20 -04:00
funcstart := int32 ( len ( ftab . P ) )
2016-04-06 12:01:40 -07:00
funcstart += int32 ( - len ( ftab . P ) ) & ( int32 ( SysArch . PtrSize ) - 1 )
2015-02-27 22:57:28 -05:00
2016-09-17 10:01:17 -04:00
setaddr ( ctxt , ftab , 8 + int64 ( SysArch . PtrSize ) + int64 ( nfunc ) * 2 * int64 ( SysArch . PtrSize ) , s )
2016-08-19 22:40:38 -04:00
setuintxx ( ctxt , ftab , 8 + int64 ( SysArch . PtrSize ) + int64 ( nfunc ) * 2 * int64 ( SysArch . PtrSize ) + int64 ( SysArch . PtrSize ) , uint64 ( funcstart ) , int64 ( SysArch . PtrSize ) )
2015-02-27 22:57:28 -05:00
2016-12-14 13:24:21 -05:00
// Write runtime._func. Keep in sync with ../../../../runtime/runtime2.go:/_func
// and package debug/gosym.
2015-02-27 22:57:28 -05:00
// fixed size of struct, checked below
2016-04-20 14:22:20 -04:00
off := funcstart
2015-02-27 22:57:28 -05:00
2016-04-20 14:22:20 -04:00
end := funcstart + int32 ( SysArch . PtrSize ) + 3 * 4 + 5 * 4 + int32 ( len ( pcln . Pcdata ) ) * 4 + int32 ( len ( pcln . Funcdata ) ) * int32 ( SysArch . PtrSize )
2016-04-06 12:01:40 -07:00
if len ( pcln . Funcdata ) > 0 && ( end & int32 ( SysArch . PtrSize - 1 ) != 0 ) {
2015-02-27 22:57:28 -05:00
end += 4
}
2016-09-20 15:31:26 +12:00
Symgrow ( ftab , int64 ( end ) )
2015-02-27 22:57:28 -05:00
// entry uintptr
2016-09-17 10:01:17 -04:00
off = int32 ( setaddr ( ctxt , ftab , int64 ( off ) , s ) )
2015-02-27 22:57:28 -05:00
// name int32
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
nameoff := nameToOffset ( s . Name )
off = int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , uint32 ( nameoff ) ) )
2015-02-27 22:57:28 -05:00
// args int32
// TODO: Move into funcinfo.
2016-04-11 22:19:34 +03:00
args := uint32 ( 0 )
2016-09-17 10:01:17 -04:00
if s . FuncInfo != nil {
args = uint32 ( s . FuncInfo . Args )
2016-04-11 22:19:34 +03:00
}
2016-08-19 22:40:38 -04:00
off = int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , args ) )
2015-02-27 22:57:28 -05:00
// frame int32
2015-03-04 16:50:59 -05:00
// This has been removed (it was never set quite correctly anyway).
// Nothing should use it.
// Leave an obviously incorrect value.
// TODO: Remove entirely.
2016-08-19 22:40:38 -04:00
off = int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , 0x1234567 ) )
2015-02-27 22:57:28 -05:00
2016-08-22 10:33:13 -04:00
if pcln != & pclntabZpcln {
2016-08-19 22:40:38 -04:00
renumberfiles ( ctxt , pcln . File , & pcln . Pcfile )
2015-02-27 22:57:28 -05:00
if false {
// Sanity check the new numbering
2016-04-20 14:22:20 -04:00
var it Pciter
2016-08-19 22:40:38 -04:00
for pciterinit ( ctxt , & it , & pcln . Pcfile ) ; it . done == 0 ; pciternext ( & it ) {
if it . value < 1 || it . value > int32 ( len ( ctxt . Filesyms ) ) {
2016-09-17 10:01:17 -04:00
Errorf ( s , "bad file number in pcfile: %d not in range [1, %d]\n" , it . value , len ( ctxt . Filesyms ) )
2015-04-09 07:37:17 -04:00
errorexit ( )
2015-02-27 22:57:28 -05:00
}
}
}
}
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
if len ( pcln . InlTree ) > 0 {
inlTreeSym := ctxt . Syms . Lookup ( "inltree." + s . Name , 0 )
inlTreeSym . Type = obj . SRODATA
inlTreeSym . Attr |= AttrReachable | AttrDuplicateOK
for i , call := range pcln . InlTree {
// Usually, call.File is already numbered since the file
// shows up in the Pcfile table. However, two inlined calls
// might overlap exactly so that only the innermost file
// appears in the Pcfile table. In that case, this assigns
// the outer file a number.
numberfile ( ctxt , call . File )
nameoff := nameToOffset ( call . Func . Name )
setuint32 ( ctxt , inlTreeSym , int64 ( i * 16 + 0 ) , uint32 ( call . Parent ) )
setuint32 ( ctxt , inlTreeSym , int64 ( i * 16 + 4 ) , uint32 ( call . File . Value ) )
setuint32 ( ctxt , inlTreeSym , int64 ( i * 16 + 8 ) , uint32 ( call . Line ) )
setuint32 ( ctxt , inlTreeSym , int64 ( i * 16 + 12 ) , uint32 ( nameoff ) )
}
pcln . Funcdata [ obj . FUNCDATA_InlTree ] = inlTreeSym
pcln . Pcdata [ obj . PCDATA_InlTreeIndex ] = pcln . Pcinline
}
2015-02-27 22:57:28 -05:00
// pcdata
2016-08-19 22:40:38 -04:00
off = addpctab ( ctxt , ftab , off , & pcln . Pcsp )
2015-02-27 22:57:28 -05:00
2016-08-19 22:40:38 -04:00
off = addpctab ( ctxt , ftab , off , & pcln . Pcfile )
off = addpctab ( ctxt , ftab , off , & pcln . Pcline )
off = int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , uint32 ( len ( pcln . Pcdata ) ) ) )
off = int32 ( setuint32 ( ctxt , ftab , int64 ( off ) , uint32 ( len ( pcln . Funcdata ) ) ) )
2016-04-20 14:22:20 -04:00
for i := 0 ; i < len ( pcln . Pcdata ) ; i ++ {
2016-08-19 22:40:38 -04:00
off = addpctab ( ctxt , ftab , off , & pcln . Pcdata [ i ] )
2015-02-27 22:57:28 -05:00
}
// funcdata, must be pointer-aligned and we're only int32-aligned.
// Missing funcdata will be 0 (nil pointer).
2016-03-23 14:02:36 +02:00
if len ( pcln . Funcdata ) > 0 {
2016-04-06 12:01:40 -07:00
if off & int32 ( SysArch . PtrSize - 1 ) != 0 {
2015-02-27 22:57:28 -05:00
off += 4
}
2016-04-20 14:22:20 -04:00
for i := 0 ; i < len ( pcln . Funcdata ) ; i ++ {
2015-02-27 22:57:28 -05:00
if pcln . Funcdata [ i ] == nil {
2016-08-19 22:40:38 -04:00
setuintxx ( ctxt , ftab , int64 ( off ) + int64 ( SysArch . PtrSize ) * int64 ( i ) , uint64 ( pcln . Funcdataoff [ i ] ) , int64 ( SysArch . PtrSize ) )
2015-02-27 22:57:28 -05:00
} else {
// TODO: Dedup.
2016-08-22 10:33:13 -04:00
funcdataBytes += pcln . Funcdata [ i ] . Size
2015-02-27 22:57:28 -05:00
2016-08-19 22:40:38 -04:00
setaddrplus ( ctxt , ftab , int64 ( off ) + int64 ( SysArch . PtrSize ) * int64 ( i ) , pcln . Funcdata [ i ] , pcln . Funcdataoff [ i ] )
2015-02-27 22:57:28 -05:00
}
}
2016-04-06 12:01:40 -07:00
off += int32 ( len ( pcln . Funcdata ) ) * int32 ( SysArch . PtrSize )
2015-02-27 22:57:28 -05:00
}
if off != end {
2016-09-17 10:01:17 -04:00
Errorf ( s , "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)" , funcstart , off , end , len ( pcln . Pcdata ) , len ( pcln . Funcdata ) , SysArch . PtrSize )
2015-04-09 07:37:17 -04:00
errorexit ( )
2015-02-27 22:57:28 -05:00
}
nfunc ++
}
2015-03-16 11:53:08 +13:00
pclntabLastFunc = last
2015-02-27 22:57:28 -05:00
// Final entry of table is just end pc.
2016-08-19 22:40:38 -04:00
setaddrplus ( ctxt , ftab , 8 + int64 ( SysArch . PtrSize ) + int64 ( nfunc ) * 2 * int64 ( SysArch . PtrSize ) , last , last . Size )
2015-02-27 22:57:28 -05:00
// Start file table.
2015-03-02 12:35:15 -05:00
start := int32 ( len ( ftab . P ) )
2015-02-27 22:57:28 -05:00
2016-04-06 12:01:40 -07:00
start += int32 ( - len ( ftab . P ) ) & ( int32 ( SysArch . PtrSize ) - 1 )
2015-03-16 11:53:08 +13:00
pclntabFiletabOffset = start
2016-08-19 22:40:38 -04:00
setuint32 ( ctxt , ftab , 8 + int64 ( SysArch . PtrSize ) + int64 ( nfunc ) * 2 * int64 ( SysArch . PtrSize ) + int64 ( SysArch . PtrSize ) , uint32 ( start ) )
2015-02-27 22:57:28 -05:00
2016-09-20 15:31:26 +12:00
Symgrow ( ftab , int64 ( start ) + ( int64 ( len ( ctxt . Filesyms ) ) + 1 ) * 4 )
2016-09-15 19:52:40 -04:00
setuint32 ( ctxt , ftab , int64 ( start ) , uint32 ( len ( ctxt . Filesyms ) + 1 ) )
2016-08-19 22:40:38 -04:00
for i := len ( ctxt . Filesyms ) - 1 ; i >= 0 ; i -- {
s := ctxt . Filesyms [ i ]
setuint32 ( ctxt , ftab , int64 ( start ) + s . Value * 4 , uint32 ( ftabaddstring ( ctxt , ftab , s . Name ) ) )
2015-02-27 22:57:28 -05:00
}
ftab . Size = int64 ( len ( ftab . P ) )
2016-08-21 18:25:28 -04:00
if ctxt . Debugvlog != 0 {
2016-08-25 12:32:42 +10:00
ctxt . Logf ( "%5.2f pclntab=%d bytes, funcdata total %d bytes\n" , obj . Cputime ( ) , ftab . Size , funcdataBytes )
2015-02-27 22:57:28 -05:00
}
}
2015-12-29 10:16:40 -05:00
func expandGoroot ( s string ) string {
const n = len ( "$GOROOT" )
if len ( s ) >= n + 1 && s [ : n ] == "$GOROOT" && ( s [ n ] == '/' || s [ n ] == '\\' ) {
2016-09-09 08:13:16 -04:00
root := obj . GOROOT
2015-12-29 10:16:40 -05:00
if final := os . Getenv ( "GOROOT_FINAL" ) ; final != "" {
root = final
}
return filepath . ToSlash ( filepath . Join ( root , s [ n : ] ) )
}
return s
}
2015-02-27 22:57:28 -05:00
const (
BUCKETSIZE = 256 * MINFUNC
SUBBUCKETS = 16
SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
NOIDX = 0x7fffffff
)
// findfunctab generates a lookup table to quickly find the containing
2016-03-01 23:21:55 +00:00
// function for a pc. See src/runtime/symtab.go:findfunc for details.
2016-08-19 22:40:38 -04:00
func ( ctxt * Link ) findfunctab ( ) {
cmd/link: use ctxt.{Lookup,ROLookup} in favour of function versions of same
Done with two eg templates:
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linklookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.Lookup(name, v)
}
package p
import (
"cmd/link/internal/ld"
)
func before(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ld.Linkrlookup(ctxt, name, v)
}
func after(ctxt *ld.Link, name string, v int) *ld.Symbol {
return ctxt.Syms.ROLookup(name, v)
}
Change-Id: I00647dbf62294557bd24c29ad1f108fc786335f1
Reviewed-on: https://go-review.googlesource.com/29343
Run-TryBot: Michael Hudson-Doyle <michael.hudson@canonical.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-09-20 15:06:08 +12:00
t := ctxt . Syms . Lookup ( "runtime.findfunctab" , 0 )
2015-04-19 19:33:58 -07:00
t . Type = obj . SRODATA
2016-03-02 07:59:49 -05:00
t . Attr |= AttrReachable
t . Attr |= AttrLocal
2015-02-27 22:57:28 -05:00
// find min and max address
2016-08-19 22:40:38 -04:00
min := ctxt . Textp [ 0 ] . Value
2015-03-02 12:35:15 -05:00
max := int64 ( 0 )
2016-08-19 22:40:38 -04:00
for _ , s := range ctxt . Textp {
2015-02-27 22:57:28 -05:00
max = s . Value + s . Size
}
// for each subbucket, compute the minimum of all symbol indexes
// that map to that subbucket.
2015-03-02 12:35:15 -05:00
n := int32 ( ( max - min + SUBBUCKETSIZE - 1 ) / SUBBUCKETSIZE )
2015-02-27 22:57:28 -05:00
2015-03-02 12:35:15 -05:00
indexes := make ( [ ] int32 , n )
for i := int32 ( 0 ) ; i < n ; i ++ {
2015-02-27 22:57:28 -05:00
indexes [ i ] = NOIDX
}
2015-03-02 12:35:15 -05:00
idx := int32 ( 0 )
2016-08-19 22:40:38 -04:00
for i , s := range ctxt . Textp {
2015-02-27 22:57:28 -05:00
if container ( s ) != 0 {
continue
}
2016-04-19 14:02:21 -04:00
p := s . Value
2016-08-19 11:35:54 -04:00
var e * Symbol
2016-04-19 14:02:21 -04:00
i ++
2016-08-19 22:40:38 -04:00
if i < len ( ctxt . Textp ) {
e = ctxt . Textp [ i ]
2016-04-19 14:02:21 -04:00
}
2016-08-19 22:40:38 -04:00
for container ( e ) != 0 && i < len ( ctxt . Textp ) {
e = ctxt . Textp [ i ]
2016-04-19 14:02:21 -04:00
i ++
2015-02-27 22:57:28 -05:00
}
2016-04-19 14:02:21 -04:00
q := max
2015-02-27 22:57:28 -05:00
if e != nil {
q = e . Value
}
//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
for ; p < q ; p += SUBBUCKETSIZE {
2016-04-19 14:02:21 -04:00
i = int ( ( p - min ) / SUBBUCKETSIZE )
2015-02-27 22:57:28 -05:00
if indexes [ i ] > idx {
indexes [ i ] = idx
}
}
2016-04-19 14:02:21 -04:00
i = int ( ( q - 1 - min ) / SUBBUCKETSIZE )
2015-02-27 22:57:28 -05:00
if indexes [ i ] > idx {
indexes [ i ] = idx
}
idx ++
}
// allocate table
2015-03-02 12:35:15 -05:00
nbuckets := int32 ( ( max - min + BUCKETSIZE - 1 ) / BUCKETSIZE )
2015-02-27 22:57:28 -05:00
2016-09-20 15:31:26 +12:00
Symgrow ( t , 4 * int64 ( nbuckets ) + int64 ( n ) )
2015-02-27 22:57:28 -05:00
// fill in table
2015-03-02 12:35:15 -05:00
for i := int32 ( 0 ) ; i < nbuckets ; i ++ {
2016-04-19 14:02:21 -04:00
base := indexes [ i * SUBBUCKETS ]
2015-02-27 22:57:28 -05:00
if base == NOIDX {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "hole in findfunctab" )
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
setuint32 ( ctxt , t , int64 ( i ) * ( 4 + SUBBUCKETS ) , uint32 ( base ) )
2016-04-19 14:02:21 -04:00
for j := int32 ( 0 ) ; j < SUBBUCKETS && i * SUBBUCKETS + j < n ; j ++ {
2015-02-27 22:57:28 -05:00
idx = indexes [ i * SUBBUCKETS + j ]
if idx == NOIDX {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "hole in findfunctab" )
2015-02-27 22:57:28 -05:00
}
if idx - base >= 256 {
2016-09-17 09:39:33 -04:00
Errorf ( nil , "too many functions in a findfunc bucket! %d/%d %d %d" , i , nbuckets , j , idx - base )
2015-02-27 22:57:28 -05:00
}
2016-08-19 22:40:38 -04:00
setuint8 ( ctxt , t , int64 ( i ) * ( 4 + SUBBUCKETS ) + 4 + int64 ( j ) , uint8 ( idx - base ) )
2015-02-27 22:57:28 -05:00
}
}
}