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.
2017-09-30 17:28:05 +00:00
// Package objfile reads Go object files for the Go linker, cmd/link.
//
// This package is similar to cmd/internal/objfile which also reads
// Go object files.
package objfile
2015-05-18 15:50:00 -04:00
2015-02-27 22:57:28 -05:00
import (
2016-03-31 18:34:02 +03:00
"bufio"
2015-02-27 22:57:28 -05:00
"bytes"
2016-04-06 21:45:29 -07:00
"cmd/internal/bio"
2016-07-28 13:04:41 -04:00
"cmd/internal/dwarf"
2018-10-26 13:53:02 -04:00
"cmd/internal/obj"
2017-04-18 12:53:25 -07:00
"cmd/internal/objabi"
2017-09-30 16:50:00 +00:00
"cmd/internal/sys"
2017-10-04 17:54:04 -04:00
"cmd/link/internal/sym"
cmd/link: add optional sanity checking for duplicate symbols
Introduce a new linker command line option "-strictdups", which
enables sanity checking of "ok to duplicate" symbols, especially
DWARF info symbols. Acceptable values are 0 (no checking) 1 (issue
warnings) and 2 (issue a fatal error checks fail).
Currently if we read a DWARF symbol (such as "go.info.PKG.FUNCTION")
from one object file, and then encounter the same symbol later on
while reading another object file, we simply discard the second one
and move on with the link, since the two should in theory be
identical.
If as a result of a compiler bug we wind up with symbols that are not
identical, this tends to (silently) result in incorrect DWARF
generation, which may or may not be discovered depending on who is
consuming the DWARF and what's being done with it.
When this option is turned on, at the point where a duplicate
symbol is detected in the object file reader, we check to make sure
that the length/contents of the symbol are the same as the previously
read symbol, and print a descriptive warning (or error) if not.
For the time being this can be used for one-off testing to find
problems; at some point it would be nice if we can enable it by
default.
Updates #30908.
Change-Id: I64c4e07c326b4572db674ff17c93307e2eec607c
Reviewed-on: https://go-review.googlesource.com/c/go/+/168410
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2019-03-21 09:20:11 -04:00
"fmt"
2016-03-31 18:34:02 +03:00
"io"
2015-02-27 22:57:28 -05:00
"log"
cmd/link: add optional sanity checking for duplicate symbols
Introduce a new linker command line option "-strictdups", which
enables sanity checking of "ok to duplicate" symbols, especially
DWARF info symbols. Acceptable values are 0 (no checking) 1 (issue
warnings) and 2 (issue a fatal error checks fail).
Currently if we read a DWARF symbol (such as "go.info.PKG.FUNCTION")
from one object file, and then encounter the same symbol later on
while reading another object file, we simply discard the second one
and move on with the link, since the two should in theory be
identical.
If as a result of a compiler bug we wind up with symbols that are not
identical, this tends to (silently) result in incorrect DWARF
generation, which may or may not be discovered depending on who is
consuming the DWARF and what's being done with it.
When this option is turned on, at the point where a duplicate
symbol is detected in the object file reader, we check to make sure
that the length/contents of the symbol are the same as the previously
read symbol, and print a descriptive warning (or error) if not.
For the time being this can be used for one-off testing to find
problems; at some point it would be nice if we can enable it by
default.
Updates #30908.
Change-Id: I64c4e07c326b4572db674ff17c93307e2eec607c
Reviewed-on: https://go-review.googlesource.com/c/go/+/168410
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2019-03-21 09:20:11 -04:00
"os"
2015-02-27 22:57:28 -05:00
"strconv"
"strings"
2019-04-25 10:35:47 -04:00
"unsafe"
2015-02-27 22:57:28 -05:00
)
2015-03-06 11:42:53 -08:00
const (
2019-08-22 12:18:28 -04:00
startmagic = "\x00go114ld"
endmagic = "\xffgo114ld"
2015-03-06 11:42:53 -08:00
)
2015-02-27 22:57:28 -05:00
2016-03-31 18:34:02 +03:00
var emptyPkg = [ ] byte ( ` "". ` )
// objReader reads Go object files.
type objReader struct {
2019-04-04 00:29:16 -04:00
rd * bio . Reader
2017-09-30 16:50:00 +00:00
arch * sys . Arch
2017-10-04 17:54:04 -04:00
syms * sym . Symbols
2017-10-04 18:13:35 -04:00
lib * sym . Library
2019-08-09 11:36:03 -04:00
unit * sym . CompilationUnit
2016-09-20 15:46:37 +12:00
pn string
2017-10-04 17:54:04 -04:00
dupSym * sym . Symbol
2016-09-20 15:46:37 +12:00
localSymVersion int
cmd/link: add optional sanity checking for duplicate symbols
Introduce a new linker command line option "-strictdups", which
enables sanity checking of "ok to duplicate" symbols, especially
DWARF info symbols. Acceptable values are 0 (no checking) 1 (issue
warnings) and 2 (issue a fatal error checks fail).
Currently if we read a DWARF symbol (such as "go.info.PKG.FUNCTION")
from one object file, and then encounter the same symbol later on
while reading another object file, we simply discard the second one
and move on with the link, since the two should in theory be
identical.
If as a result of a compiler bug we wind up with symbols that are not
identical, this tends to (silently) result in incorrect DWARF
generation, which may or may not be discovered depending on who is
consuming the DWARF and what's being done with it.
When this option is turned on, at the point where a duplicate
symbol is detected in the object file reader, we check to make sure
that the length/contents of the symbol are the same as the previously
read symbol, and print a descriptive warning (or error) if not.
For the time being this can be used for one-off testing to find
problems; at some point it would be nice if we can enable it by
default.
Updates #30908.
Change-Id: I64c4e07c326b4572db674ff17c93307e2eec607c
Reviewed-on: https://go-review.googlesource.com/c/go/+/168410
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2019-03-21 09:20:11 -04:00
flags int
2019-03-26 12:02:36 -04:00
strictDupMsgs int
2019-04-04 00:29:16 -04:00
dataSize int
2016-03-31 18:34:02 +03:00
// rdBuf is used by readString and readSymName as scratch for reading strings.
rdBuf [ ] byte
2016-09-20 15:46:37 +12:00
// List of symbol references for the file being read.
2017-10-04 17:54:04 -04:00
refs [ ] * sym . Symbol
2016-03-31 18:34:02 +03:00
data [ ] byte
2017-10-04 17:54:04 -04:00
reloc [ ] sym . Reloc
pcdata [ ] sym . Pcdata
funcdata [ ] * sym . Symbol
2016-03-31 18:34:02 +03:00
funcdataoff [ ] int64
2017-10-04 17:54:04 -04:00
file [ ] * sym . Symbol
2019-05-08 15:44:49 -04:00
pkgpref string // objabi.PathToPrefix(r.lib.Pkg) + "."
2019-04-04 00:29:16 -04:00
2019-05-08 15:44:49 -04:00
roObject [ ] byte // from read-only mmap of object file (may be nil)
roOffset int64 // offset into readonly object data examined so far
2019-04-25 10:35:47 -04:00
2019-04-04 00:29:16 -04:00
dataReadOnly bool // whether data is backed by read-only memory
2016-03-31 18:34:02 +03:00
}
cmd/link: add optional sanity checking for duplicate symbols
Introduce a new linker command line option "-strictdups", which
enables sanity checking of "ok to duplicate" symbols, especially
DWARF info symbols. Acceptable values are 0 (no checking) 1 (issue
warnings) and 2 (issue a fatal error checks fail).
Currently if we read a DWARF symbol (such as "go.info.PKG.FUNCTION")
from one object file, and then encounter the same symbol later on
while reading another object file, we simply discard the second one
and move on with the link, since the two should in theory be
identical.
If as a result of a compiler bug we wind up with symbols that are not
identical, this tends to (silently) result in incorrect DWARF
generation, which may or may not be discovered depending on who is
consuming the DWARF and what's being done with it.
When this option is turned on, at the point where a duplicate
symbol is detected in the object file reader, we check to make sure
that the length/contents of the symbol are the same as the previously
read symbol, and print a descriptive warning (or error) if not.
For the time being this can be used for one-off testing to find
problems; at some point it would be nice if we can enable it by
default.
Updates #30908.
Change-Id: I64c4e07c326b4572db674ff17c93307e2eec607c
Reviewed-on: https://go-review.googlesource.com/c/go/+/168410
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2019-03-21 09:20:11 -04:00
// Flags to enable optional behavior during object loading/reading.
const (
NoFlag int = iota
// Sanity-check duplicate symbol contents, issuing warning
// when duplicates have different lengths or contents.
StrictDupsWarnFlag
// Similar to StrictDupsWarnFlag, but issue fatal error.
StrictDupsErrFlag
)
2017-09-30 17:28:05 +00:00
// Load loads an object file f into library lib.
// The symbols loaded are added to syms.
2019-08-09 11:36:03 -04:00
func Load ( arch * sys . Arch , syms * sym . Symbols , f * bio . Reader , lib * sym . Library , unit * sym . CompilationUnit , length int64 , pn string , flags int ) int {
2016-04-08 19:14:03 +10:00
start := f . Offset ( )
2019-04-25 10:35:47 -04:00
roObject := f . SliceRO ( uint64 ( length ) )
if roObject != nil {
2019-05-08 18:46:04 -04:00
f . MustSeek ( int64 ( - length ) , os . SEEK_CUR )
2019-04-25 10:35:47 -04:00
}
2016-03-31 18:34:02 +03:00
r := & objReader {
2019-04-04 00:29:16 -04:00
rd : f ,
2016-09-14 14:47:12 -04:00
lib : lib ,
2019-08-09 11:36:03 -04:00
unit : unit ,
2017-09-30 16:50:00 +00:00
arch : arch ,
syms : syms ,
2016-09-20 15:46:37 +12:00
pn : pn ,
2017-10-04 17:54:04 -04:00
dupSym : & sym . Symbol { Name : ".dup" } ,
2017-09-30 16:50:00 +00:00
localSymVersion : syms . IncVersion ( ) ,
cmd/link: add optional sanity checking for duplicate symbols
Introduce a new linker command line option "-strictdups", which
enables sanity checking of "ok to duplicate" symbols, especially
DWARF info symbols. Acceptable values are 0 (no checking) 1 (issue
warnings) and 2 (issue a fatal error checks fail).
Currently if we read a DWARF symbol (such as "go.info.PKG.FUNCTION")
from one object file, and then encounter the same symbol later on
while reading another object file, we simply discard the second one
and move on with the link, since the two should in theory be
identical.
If as a result of a compiler bug we wind up with symbols that are not
identical, this tends to (silently) result in incorrect DWARF
generation, which may or may not be discovered depending on who is
consuming the DWARF and what's being done with it.
When this option is turned on, at the point where a duplicate
symbol is detected in the object file reader, we check to make sure
that the length/contents of the symbol are the same as the previously
read symbol, and print a descriptive warning (or error) if not.
For the time being this can be used for one-off testing to find
problems; at some point it would be nice if we can enable it by
default.
Updates #30908.
Change-Id: I64c4e07c326b4572db674ff17c93307e2eec607c
Reviewed-on: https://go-review.googlesource.com/c/go/+/168410
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2019-03-21 09:20:11 -04:00
flags : flags ,
2019-04-25 10:35:47 -04:00
roObject : roObject ,
2019-05-08 15:44:49 -04:00
pkgpref : objabi . PathToPrefix ( lib . Pkg ) + "." ,
2016-03-31 18:34:02 +03:00
}
r . loadObjFile ( )
2019-05-08 15:44:49 -04:00
if roObject != nil {
if r . roOffset != length {
log . Fatalf ( "%s: unexpected end at %d, want %d" , pn , r . roOffset , start + length )
}
2019-05-08 18:46:04 -04:00
r . rd . MustSeek ( int64 ( length ) , os . SEEK_CUR )
2019-05-08 15:44:49 -04:00
} else if f . Offset ( ) != start + length {
2016-04-08 19:14:03 +10:00
log . Fatalf ( "%s: unexpected end at %d, want %d" , pn , f . Offset ( ) , start + length )
2016-03-31 18:34:02 +03:00
}
2019-03-26 12:02:36 -04:00
return r . strictDupMsgs
2016-03-31 18:34:02 +03:00
}
func ( r * objReader ) loadObjFile ( ) {
// Magic header
2015-03-02 14:22:05 -05:00
var buf [ 8 ] uint8
2016-03-31 18:34:02 +03:00
r . readFull ( buf [ : ] )
2015-02-27 22:57:28 -05:00
if string ( buf [ : ] ) != startmagic {
2016-03-31 18:34:02 +03:00
log . Fatalf ( "%s: invalid file start %x %x %x %x %x %x %x %x" , r . pn , buf [ 0 ] , buf [ 1 ] , buf [ 2 ] , buf [ 3 ] , buf [ 4 ] , buf [ 5 ] , buf [ 6 ] , buf [ 7 ] )
2015-02-27 22:57:28 -05:00
}
2016-03-31 18:34:02 +03:00
// Version
2019-05-08 15:44:49 -04:00
c , err := r . readByte ( )
2016-03-31 18:34:02 +03:00
if err != nil || c != 1 {
log . Fatalf ( "%s: invalid file version number %d" , r . pn , c )
2015-02-27 22:57:28 -05:00
}
2016-03-31 18:34:02 +03:00
// Autolib
2015-02-27 22:57:28 -05:00
for {
2016-03-31 18:34:02 +03:00
lib := r . readString ( )
2015-02-27 22:57:28 -05:00
if lib == "" {
break
}
2017-10-04 18:13:35 -04:00
r . lib . ImportStrings = append ( r . lib . ImportStrings , lib )
2015-02-27 22:57:28 -05:00
}
2019-08-22 12:18:28 -04:00
// DWARF strings
count := r . readInt ( )
r . unit . DWARFFileTable = make ( [ ] string , count )
for i := 0 ; i < count ; i ++ {
// TODO: This should probably be a call to mkROString.
r . unit . DWARFFileTable [ i ] = r . readString ( )
}
2017-09-30 17:28:05 +00:00
// Symbol references
2017-10-04 17:54:04 -04:00
r . refs = [ ] * sym . Symbol { nil } // zeroth ref is nil
2016-03-14 22:57:58 +02:00
for {
2019-05-08 15:44:49 -04:00
c , err := r . peek ( 1 )
2016-03-14 22:57:58 +02:00
if err != nil {
2016-03-31 18:34:02 +03:00
log . Fatalf ( "%s: peeking: %v" , r . pn , err )
2016-03-14 22:57:58 +02:00
}
if c [ 0 ] == 0xff {
2019-05-08 15:44:49 -04:00
r . readByte ( )
2016-03-14 22:57:58 +02:00
break
}
2016-03-31 18:34:02 +03:00
r . readRef ( )
2016-03-14 22:57:58 +02:00
}
2016-03-31 18:34:02 +03:00
// Lengths
r . readSlices ( )
2016-03-23 00:44:07 +02:00
2016-03-31 18:34:02 +03:00
// Data section
2019-04-25 10:35:47 -04:00
err = r . readDataSection ( )
2019-04-04 00:29:16 -04:00
if err != nil {
log . Fatalf ( "%s: error reading %s" , r . pn , err )
}
2016-03-21 10:55:20 +13:00
2016-03-31 18:34:02 +03:00
// Defined symbols
2015-02-27 22:57:28 -05:00
for {
2019-05-08 15:44:49 -04:00
c , err := r . peek ( 1 )
2015-04-27 12:53:34 -04:00
if err != nil {
2016-03-31 18:34:02 +03:00
log . Fatalf ( "%s: peeking: %v" , r . pn , err )
2015-04-27 12:53:34 -04:00
}
if c [ 0 ] == 0xff {
2015-02-27 22:57:28 -05:00
break
}
2016-03-31 18:34:02 +03:00
r . readSym ( )
2015-02-27 22:57:28 -05:00
}
2016-03-31 18:34:02 +03:00
// Magic footer
2015-02-27 22:57:28 -05:00
buf = [ 8 ] uint8 { }
2016-03-31 18:34:02 +03:00
r . readFull ( buf [ : ] )
2015-02-27 22:57:28 -05:00
if string ( buf [ : ] ) != endmagic {
2016-03-31 18:34:02 +03:00
log . Fatalf ( "%s: invalid file end" , r . pn )
2015-02-27 22:57:28 -05:00
}
}
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readSlices ( ) {
2019-04-04 00:29:16 -04:00
r . dataSize = r . readInt ( )
2016-03-31 18:34:02 +03:00
n := r . readInt ( )
2017-10-04 17:54:04 -04:00
r . reloc = make ( [ ] sym . Reloc , n )
2016-03-31 18:34:02 +03:00
n = r . readInt ( )
2017-10-04 17:54:04 -04:00
r . pcdata = make ( [ ] sym . Pcdata , n )
2019-09-26 10:01:42 -04:00
_ = r . readInt ( ) // TODO: remove on next object file rev (autom count)
2016-03-31 18:34:02 +03:00
n = r . readInt ( )
2017-10-04 17:54:04 -04:00
r . funcdata = make ( [ ] * sym . Symbol , n )
2016-03-31 18:34:02 +03:00
r . funcdataoff = make ( [ ] int64 , n )
n = r . readInt ( )
2017-10-04 17:54:04 -04:00
r . file = make ( [ ] * sym . Symbol , n )
2016-03-23 00:44:07 +02:00
}
2019-04-25 10:35:47 -04:00
func ( r * objReader ) readDataSection ( ) ( err error ) {
if r . roObject != nil {
r . data , r . dataReadOnly , err =
2019-05-08 15:44:49 -04:00
r . roObject [ r . roOffset : r . roOffset + int64 ( r . dataSize ) ] , true , nil
r . roOffset += int64 ( r . dataSize )
2019-04-25 10:35:47 -04:00
return
}
r . data , r . dataReadOnly , err = r . rd . Slice ( uint64 ( r . dataSize ) )
return
}
2016-03-31 18:34:02 +03:00
// Symbols are prefixed so their content doesn't get confused with the magic footer.
const symPrefix = 0xfe
2016-03-23 00:44:07 +02:00
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readSym ( ) {
2017-04-28 08:07:56 +12:00
var c byte
var err error
2019-05-08 15:44:49 -04:00
if c , err = r . readByte ( ) ; c != symPrefix || err != nil {
2016-03-31 18:34:02 +03:00
log . Fatalln ( "readSym out of sync" )
2015-02-27 22:57:28 -05:00
}
2019-05-08 15:44:49 -04:00
if c , err = r . readByte ( ) ; err != nil {
2017-04-28 08:07:56 +12:00
log . Fatalln ( "error reading input: " , err )
}
2017-10-04 17:54:04 -04:00
t := sym . AbiSymKindToSymKind [ c ]
2016-03-31 18:34:02 +03:00
s := r . readSymIndex ( )
flags := r . readInt ( )
2016-03-02 07:59:49 -05:00
dupok := flags & 1 != 0
local := flags & 2 != 0
2016-10-19 07:33:16 +03:00
makeTypelink := flags & 4 != 0
2016-03-31 18:34:02 +03:00
size := r . readInt ( )
typ := r . readSymIndex ( )
data := r . readData ( )
nreloc := r . readInt ( )
2016-03-23 00:44:07 +02:00
isdup := false
2015-02-27 22:57:28 -05:00
2017-10-04 17:54:04 -04:00
var dup * sym . Symbol
if s . Type != 0 && s . Type != sym . SXREF {
if ( t == sym . SDATA || t == sym . SBSS || t == sym . SNOPTRBSS ) && len ( data ) == 0 && nreloc == 0 {
2015-02-27 22:57:28 -05:00
if s . Size < int64 ( size ) {
s . Size = int64 ( size )
}
if typ != nil && s . Gotype == nil {
s . Gotype = typ
}
return
}
2017-10-04 17:54:04 -04:00
if ( s . Type == sym . SDATA || s . Type == sym . SBSS || s . Type == sym . SNOPTRBSS ) && len ( s . P ) == 0 && len ( s . R ) == 0 {
2015-02-27 22:57:28 -05:00
goto overwrite
}
2017-10-04 17:54:04 -04:00
if s . Type != sym . SBSS && s . Type != sym . SNOPTRBSS && ! dupok && ! s . Attr . DuplicateOK ( ) {
2016-03-31 18:34:02 +03:00
log . Fatalf ( "duplicate symbol %s (types %d and %d) in %s and %s" , s . Name , s . Type , t , s . File , r . pn )
2015-02-27 22:57:28 -05:00
}
if len ( s . P ) > 0 {
dup = s
2016-03-31 18:34:02 +03:00
s = r . dupSym
2016-03-23 00:44:07 +02:00
isdup = true
2015-02-27 22:57:28 -05:00
}
}
overwrite :
2019-05-08 15:44:49 -04:00
s . File = r . pkgpref [ : len ( r . pkgpref ) - 1 ]
2019-08-09 11:36:03 -04:00
s . Unit = r . unit
2016-03-02 07:59:49 -05:00
if dupok {
2017-10-04 17:54:04 -04:00
s . Attr |= sym . AttrDuplicateOK
2016-03-02 07:59:49 -05:00
}
2017-10-04 17:54:04 -04:00
if t == sym . SXREF {
2015-02-27 22:57:28 -05:00
log . Fatalf ( "bad sxref" )
}
if t == 0 {
2016-03-31 18:34:02 +03:00
log . Fatalf ( "missing type for %s in %s" , s . Name , r . pn )
2015-02-27 22:57:28 -05:00
}
2017-10-04 17:54:04 -04:00
if t == sym . SBSS && ( s . Type == sym . SRODATA || s . Type == sym . SNOPTRBSS ) {
2016-09-07 14:45:27 -04:00
t = s . Type
2015-02-27 22:57:28 -05:00
}
2016-09-07 14:45:27 -04:00
s . Type = t
2015-02-27 22:57:28 -05:00
if s . Size < int64 ( size ) {
s . Size = int64 ( size )
}
2017-10-04 17:54:04 -04:00
s . Attr . Set ( sym . AttrLocal , local )
s . Attr . Set ( sym . AttrMakeTypelink , makeTypelink )
2016-03-21 17:29:29 +13:00
if typ != nil {
2015-02-27 22:57:28 -05:00
s . Gotype = typ
}
2016-03-23 00:44:07 +02:00
if isdup && typ != nil { // if bss sym defined multiple times, take type from any one def
2015-02-27 22:57:28 -05:00
dup . Gotype = typ
}
s . P = data
2019-04-04 00:29:16 -04:00
s . Attr . Set ( sym . AttrReadOnly , r . dataReadOnly )
2015-02-27 22:57:28 -05:00
if nreloc > 0 {
2016-03-31 18:34:02 +03:00
s . R = r . reloc [ : nreloc : nreloc ]
2016-03-23 00:44:07 +02:00
if ! isdup {
2016-03-31 18:34:02 +03:00
r . reloc = r . reloc [ nreloc : ]
2016-03-23 00:44:07 +02:00
}
2015-03-02 12:35:15 -05:00
for i := 0 ; i < nreloc ; i ++ {
2017-10-04 17:54:04 -04:00
s . R [ i ] = sym . Reloc {
2016-03-31 18:34:02 +03:00
Off : r . readInt32 ( ) ,
Siz : r . readUint8 ( ) ,
2017-04-18 12:53:25 -07:00
Type : objabi . RelocType ( r . readInt32 ( ) ) ,
2016-03-31 18:34:02 +03:00
Add : r . readInt64 ( ) ,
Sym : r . readSymIndex ( ) ,
}
2015-02-27 22:57:28 -05:00
}
}
2017-10-04 17:54:04 -04:00
if s . Type == sym . STEXT {
s . FuncInfo = new ( sym . FuncInfo )
2016-04-12 23:18:47 +03:00
pc := s . FuncInfo
2016-04-11 22:19:34 +03:00
pc . Args = r . readInt32 ( )
pc . Locals = r . readInt32 ( )
2016-03-31 18:34:02 +03:00
if r . readUint8 ( ) != 0 {
2017-10-04 17:54:04 -04:00
s . Attr |= sym . AttrNoSplit
2016-03-02 07:59:49 -05:00
}
2016-03-31 18:34:02 +03:00
flags := r . readInt ( )
2016-03-10 16:15:26 -05:00
if flags & ( 1 << 2 ) != 0 {
2017-10-04 17:54:04 -04:00
s . Attr |= sym . AttrReflectMethod
2016-03-10 16:15:26 -05:00
}
2017-05-09 14:34:16 -07:00
if flags & ( 1 << 3 ) != 0 {
2017-10-04 17:54:04 -04:00
s . Attr |= sym . AttrShared
2017-05-09 14:34:16 -07:00
}
2019-03-28 12:51:30 -04:00
if flags & ( 1 << 4 ) != 0 {
s . Attr |= sym . AttrTopFrame
}
2016-03-31 18:34:02 +03:00
n := r . readInt ( )
2019-09-26 10:01:42 -04:00
if n != 0 {
log . Fatalf ( "stale object file: autom count nonzero" )
2016-03-23 00:44:07 +02:00
}
2016-03-31 18:34:02 +03:00
pc . Pcsp . P = r . readData ( )
pc . Pcfile . P = r . readData ( )
pc . Pcline . P = r . readData ( )
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
pc . Pcinline . P = r . readData ( )
2016-03-31 18:34:02 +03:00
n = r . readInt ( )
pc . Pcdata = r . pcdata [ : n : n ]
2016-03-23 00:44:07 +02:00
if ! isdup {
2016-03-31 18:34:02 +03:00
r . pcdata = r . pcdata [ n : ]
2016-03-23 00:44:07 +02:00
}
2015-03-02 12:35:15 -05:00
for i := 0 ; i < n ; i ++ {
2016-03-31 18:34:02 +03:00
pc . Pcdata [ i ] . P = r . readData ( )
2015-02-27 22:57:28 -05:00
}
2016-03-31 18:34:02 +03:00
n = r . readInt ( )
pc . Funcdata = r . funcdata [ : n : n ]
pc . Funcdataoff = r . funcdataoff [ : n : n ]
2016-03-23 00:44:07 +02:00
if ! isdup {
2016-03-31 18:34:02 +03:00
r . funcdata = r . funcdata [ n : ]
r . funcdataoff = r . funcdataoff [ n : ]
2016-03-23 00:44:07 +02:00
}
2015-03-02 12:35:15 -05:00
for i := 0 ; i < n ; i ++ {
2016-03-31 18:34:02 +03:00
pc . Funcdata [ i ] = r . readSymIndex ( )
2015-02-27 22:57:28 -05:00
}
2015-03-02 12:35:15 -05:00
for i := 0 ; i < n ; i ++ {
2016-03-31 18:34:02 +03:00
pc . Funcdataoff [ i ] = r . readInt64 ( )
2015-02-27 22:57:28 -05:00
}
2016-03-31 18:34:02 +03:00
n = r . readInt ( )
pc . File = r . file [ : n : n ]
2016-03-23 00:44:07 +02:00
if ! isdup {
2016-03-31 18:34:02 +03:00
r . file = r . file [ n : ]
2016-03-23 00:44:07 +02:00
}
2015-03-02 12:35:15 -05:00
for i := 0 ; i < n ; i ++ {
2016-03-31 18:34:02 +03:00
pc . File [ i ] = r . readSymIndex ( )
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
n = r . readInt ( )
2017-10-04 17:54:04 -04:00
pc . InlTree = make ( [ ] sym . InlinedCall , n )
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
for i := 0 ; i < n ; i ++ {
pc . InlTree [ i ] . Parent = r . readInt32 ( )
pc . InlTree [ i ] . File = r . readSymIndex ( )
pc . InlTree [ i ] . Line = r . readInt32 ( )
2019-10-08 17:22:20 -04:00
pc . InlTree [ i ] . Func = r . readSymIndex ( ) . Name
2018-12-04 07:58:18 -08:00
pc . InlTree [ i ] . ParentPC = r . readInt32 ( )
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
}
2015-02-27 22:57:28 -05:00
2016-09-14 14:47:12 -04:00
if ! dupok {
2016-03-02 07:59:49 -05:00
if s . Attr . OnList ( ) {
2015-02-27 22:57:28 -05:00
log . Fatalf ( "symbol %s listed multiple times" , s . Name )
}
2017-10-04 17:54:04 -04:00
s . Attr |= sym . AttrOnList
2017-10-04 18:13:35 -04:00
r . lib . Textp = append ( r . lib . Textp , s )
2016-09-14 14:47:12 -04:00
} else {
// there may ba a dup in another package
// put into a temp list and add to text later
if ! isdup {
2017-10-04 18:13:35 -04:00
r . lib . DupTextSyms = append ( r . lib . DupTextSyms , s )
2016-09-14 14:47:12 -04:00
} else {
2017-10-04 18:13:35 -04:00
r . lib . DupTextSyms = append ( r . lib . DupTextSyms , dup )
2016-09-14 14:47:12 -04:00
}
2015-02-27 22:57:28 -05:00
}
}
2017-10-04 17:54:04 -04:00
if s . Type == sym . SDWARFINFO {
2016-07-28 13:04:41 -04:00
r . patchDWARFName ( s )
}
cmd/link: add optional sanity checking for duplicate symbols
Introduce a new linker command line option "-strictdups", which
enables sanity checking of "ok to duplicate" symbols, especially
DWARF info symbols. Acceptable values are 0 (no checking) 1 (issue
warnings) and 2 (issue a fatal error checks fail).
Currently if we read a DWARF symbol (such as "go.info.PKG.FUNCTION")
from one object file, and then encounter the same symbol later on
while reading another object file, we simply discard the second one
and move on with the link, since the two should in theory be
identical.
If as a result of a compiler bug we wind up with symbols that are not
identical, this tends to (silently) result in incorrect DWARF
generation, which may or may not be discovered depending on who is
consuming the DWARF and what's being done with it.
When this option is turned on, at the point where a duplicate
symbol is detected in the object file reader, we check to make sure
that the length/contents of the symbol are the same as the previously
read symbol, and print a descriptive warning (or error) if not.
For the time being this can be used for one-off testing to find
problems; at some point it would be nice if we can enable it by
default.
Updates #30908.
Change-Id: I64c4e07c326b4572db674ff17c93307e2eec607c
Reviewed-on: https://go-review.googlesource.com/c/go/+/168410
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2019-03-21 09:20:11 -04:00
if isdup && r . flags & ( StrictDupsWarnFlag | StrictDupsErrFlag ) != 0 {
// Compare the just-read symbol with the previously read
// symbol of the same name, verifying that they have the same
// payload. If not, issue a warning and possibly an error.
if ! bytes . Equal ( s . P , dup . P ) {
reason := "same length but different contents"
if len ( s . P ) != len ( dup . P ) {
reason = fmt . Sprintf ( "new length %d != old length %d" ,
len ( data ) , len ( dup . P ) )
}
2019-08-09 11:36:03 -04:00
fmt . Fprintf ( os . Stderr , "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n" , r . lib , dup , dup . Unit . Lib , reason )
cmd/link: add optional sanity checking for duplicate symbols
Introduce a new linker command line option "-strictdups", which
enables sanity checking of "ok to duplicate" symbols, especially
DWARF info symbols. Acceptable values are 0 (no checking) 1 (issue
warnings) and 2 (issue a fatal error checks fail).
Currently if we read a DWARF symbol (such as "go.info.PKG.FUNCTION")
from one object file, and then encounter the same symbol later on
while reading another object file, we simply discard the second one
and move on with the link, since the two should in theory be
identical.
If as a result of a compiler bug we wind up with symbols that are not
identical, this tends to (silently) result in incorrect DWARF
generation, which may or may not be discovered depending on who is
consuming the DWARF and what's being done with it.
When this option is turned on, at the point where a duplicate
symbol is detected in the object file reader, we check to make sure
that the length/contents of the symbol are the same as the previously
read symbol, and print a descriptive warning (or error) if not.
For the time being this can be used for one-off testing to find
problems; at some point it would be nice if we can enable it by
default.
Updates #30908.
Change-Id: I64c4e07c326b4572db674ff17c93307e2eec607c
Reviewed-on: https://go-review.googlesource.com/c/go/+/168410
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2019-03-21 09:20:11 -04:00
// For the moment, whitelist DWARF subprogram DIEs for
// auto-generated wrapper functions. What seems to happen
// here is that we get different line numbers on formal
// params; I am guessing that the pos is being inherited
// from the spot where the wrapper is needed.
2019-04-19 14:50:57 -04:00
whitelist := ( strings . HasPrefix ( dup . Name , "go.info.go.interface" ) ||
strings . HasPrefix ( dup . Name , "go.info.go.builtin" ) ||
2019-07-31 10:33:11 -04:00
strings . HasPrefix ( dup . Name , "go.isstmt.go.builtin" ) ||
strings . HasPrefix ( dup . Name , "go.debuglines" ) )
2019-03-26 12:02:36 -04:00
if ! whitelist {
r . strictDupMsgs ++
cmd/link: add optional sanity checking for duplicate symbols
Introduce a new linker command line option "-strictdups", which
enables sanity checking of "ok to duplicate" symbols, especially
DWARF info symbols. Acceptable values are 0 (no checking) 1 (issue
warnings) and 2 (issue a fatal error checks fail).
Currently if we read a DWARF symbol (such as "go.info.PKG.FUNCTION")
from one object file, and then encounter the same symbol later on
while reading another object file, we simply discard the second one
and move on with the link, since the two should in theory be
identical.
If as a result of a compiler bug we wind up with symbols that are not
identical, this tends to (silently) result in incorrect DWARF
generation, which may or may not be discovered depending on who is
consuming the DWARF and what's being done with it.
When this option is turned on, at the point where a duplicate
symbol is detected in the object file reader, we check to make sure
that the length/contents of the symbol are the same as the previously
read symbol, and print a descriptive warning (or error) if not.
For the time being this can be used for one-off testing to find
problems; at some point it would be nice if we can enable it by
default.
Updates #30908.
Change-Id: I64c4e07c326b4572db674ff17c93307e2eec607c
Reviewed-on: https://go-review.googlesource.com/c/go/+/168410
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2019-03-21 09:20:11 -04:00
}
}
}
2016-07-28 13:04:41 -04:00
}
2017-10-04 17:54:04 -04:00
func ( r * objReader ) patchDWARFName ( s * sym . Symbol ) {
2016-07-28 13:04:41 -04:00
// This is kind of ugly. Really the package name should not
// even be included here.
if s . Size < 1 || s . P [ 0 ] != dwarf . DW_ABRV_FUNCTION {
return
}
e := bytes . IndexByte ( s . P , 0 )
if e == - 1 {
return
}
p := bytes . Index ( s . P [ : e ] , emptyPkg )
if p == - 1 {
return
}
2019-05-08 15:44:49 -04:00
pkgprefix := [ ] byte ( r . pkgpref )
2016-07-28 13:04:41 -04:00
patched := bytes . Replace ( s . P [ : e ] , emptyPkg , pkgprefix , - 1 )
s . P = append ( patched , s . P [ e : ] ... )
delta := int64 ( len ( s . P ) ) - s . Size
s . Size = int64 ( len ( s . P ) )
for i := range s . R {
r := & s . R [ i ]
if r . Off > int32 ( e ) {
r . Off += int32 ( delta )
}
}
2015-02-27 22:57:28 -05:00
}
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readFull ( b [ ] byte ) {
2019-05-08 15:44:49 -04:00
if r . roObject != nil {
copy ( b , r . roObject [ r . roOffset : ] )
r . roOffset += int64 ( len ( b ) )
return
}
2016-03-31 18:34:02 +03:00
_ , err := io . ReadFull ( r . rd , b )
if err != nil {
log . Fatalf ( "%s: error reading %s" , r . pn , err )
}
}
2019-05-08 15:44:49 -04:00
func ( r * objReader ) readByte ( ) ( byte , error ) {
if r . roObject != nil {
b := r . roObject [ r . roOffset ]
r . roOffset ++
return b , nil
}
return r . rd . ReadByte ( )
}
func ( r * objReader ) peek ( n int ) ( [ ] byte , error ) {
if r . roObject != nil {
return r . roObject [ r . roOffset : r . roOffset + int64 ( n ) ] , nil
}
return r . rd . Peek ( n )
}
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readRef ( ) {
2019-05-08 15:44:49 -04:00
if c , err := r . readByte ( ) ; c != symPrefix || err != nil {
2016-03-31 18:34:02 +03:00
log . Fatalf ( "readSym out of sync" )
2016-03-14 22:57:58 +02:00
}
2016-03-31 18:34:02 +03:00
name := r . readSymName ( )
2018-10-26 13:53:02 -04:00
var v int
if abi := r . readInt ( ) ; abi == - 1 {
// Static
2016-09-20 15:46:37 +12:00
v = r . localSymVersion
2018-10-26 13:53:02 -04:00
} else if abiver := sym . ABIToVersion ( obj . ABI ( abi ) ) ; abiver != - 1 {
// Note that data symbols are "ABI0", which maps to version 0.
v = abiver
} else {
log . Fatalf ( "invalid symbol ABI for %q: %d" , name , abi )
2016-03-14 22:57:58 +02:00
}
2017-09-30 16:50:00 +00:00
s := r . syms . Lookup ( name , v )
2016-03-31 18:34:02 +03:00
r . refs = append ( r . refs , s )
2016-03-20 17:22:57 +02:00
2018-10-26 13:53:02 -04:00
if s == nil || v == r . localSymVersion {
2016-03-20 17:22:57 +02:00
return
}
if s . Name [ 0 ] == '$' && len ( s . Name ) > 5 && s . Type == 0 && len ( s . P ) == 0 {
x , err := strconv . ParseUint ( s . Name [ 5 : ] , 16 , 64 )
if err != nil {
log . Panicf ( "failed to parse $-symbol %s: %v" , s . Name , err )
}
2017-10-04 17:54:04 -04:00
s . Type = sym . SRODATA
s . Attr |= sym . AttrLocal
2016-03-20 17:22:57 +02:00
switch s . Name [ : 5 ] {
case "$f32." :
if uint64 ( uint32 ( x ) ) != x {
log . Panicf ( "$-symbol %s too large: %d" , s . Name , x )
}
2017-09-30 16:50:00 +00:00
s . AddUint32 ( r . arch , uint32 ( x ) )
2016-03-20 17:22:57 +02:00
case "$f64." , "$i64." :
2017-09-30 16:50:00 +00:00
s . AddUint64 ( r . arch , x )
2016-03-20 17:22:57 +02:00
default :
log . Panicf ( "unrecognized $-symbol: %s" , s . Name )
}
2017-10-04 17:54:04 -04:00
s . Attr . Set ( sym . AttrReachable , false )
2016-03-20 17:22:57 +02:00
}
if strings . HasPrefix ( s . Name , "runtime.gcbits." ) {
2017-10-04 17:54:04 -04:00
s . Attr |= sym . AttrLocal
2016-03-20 17:22:57 +02:00
}
2016-03-14 22:57:58 +02:00
}
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readInt64 ( ) int64 {
2015-03-02 12:35:15 -05:00
uv := uint64 ( 0 )
2016-03-19 23:27:41 +02:00
for shift := uint ( 0 ) ; ; shift += 7 {
2015-02-27 22:57:28 -05:00
if shift >= 64 {
log . Fatalf ( "corrupt input" )
}
2019-05-08 15:44:49 -04:00
c , err := r . readByte ( )
2016-03-19 23:27:41 +02:00
if err != nil {
log . Fatalln ( "error reading input: " , err )
}
uv |= uint64 ( c & 0x7F ) << shift
2015-02-27 22:57:28 -05:00
if c & 0x80 == 0 {
break
}
}
2016-04-14 19:04:45 -07:00
return int64 ( uv >> 1 ) ^ ( int64 ( uv << 63 ) >> 63 )
2015-02-27 22:57:28 -05:00
}
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readInt ( ) int {
n := r . readInt64 ( )
2015-07-10 14:38:35 -07:00
if int64 ( int ( n ) ) != n {
log . Panicf ( "%v out of range for int" , n )
}
return int ( n )
}
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readInt32 ( ) int32 {
n := r . readInt64 ( )
2015-07-10 14:38:35 -07:00
if int64 ( int32 ( n ) ) != n {
log . Panicf ( "%v out of range for int32" , n )
}
return int32 ( n )
}
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readInt16 ( ) int16 {
n := r . readInt64 ( )
2015-07-10 14:38:35 -07:00
if int64 ( int16 ( n ) ) != n {
log . Panicf ( "%v out of range for int16" , n )
}
return int16 ( n )
}
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readUint8 ( ) uint8 {
n := r . readInt64 ( )
2015-07-10 14:38:35 -07:00
if int64 ( uint8 ( n ) ) != n {
log . Panicf ( "%v out of range for uint8" , n )
}
return uint8 ( n )
}
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readString ( ) string {
n := r . readInt ( )
2016-04-04 22:36:43 +03:00
if cap ( r . rdBuf ) < n {
r . rdBuf = make ( [ ] byte , 2 * n )
2016-02-28 15:59:33 -09:00
}
2016-03-31 18:34:02 +03:00
r . readFull ( r . rdBuf [ : n ] )
return string ( r . rdBuf [ : n ] )
2015-02-27 22:57:28 -05:00
}
2016-03-31 18:34:02 +03:00
func ( r * objReader ) readData ( ) [ ] byte {
n := r . readInt ( )
p := r . data [ : n : n ]
r . data = r . data [ n : ]
2015-04-24 20:24:49 -07:00
return p
2015-02-27 22:57:28 -05:00
}
2019-04-25 10:35:47 -04:00
type stringHeader struct {
str unsafe . Pointer
len int
}
func mkROString ( rodata [ ] byte ) string {
if len ( rodata ) == 0 {
return ""
}
ss := stringHeader { str : unsafe . Pointer ( & rodata [ 0 ] ) , len : len ( rodata ) }
s := * ( * string ) ( unsafe . Pointer ( & ss ) )
return s
}
2016-03-31 18:34:02 +03:00
// readSymName reads a symbol name, replacing all "". with pkg.
func ( r * objReader ) readSymName ( ) string {
n := r . readInt ( )
2015-02-27 22:57:28 -05:00
if n == 0 {
2016-03-31 18:34:02 +03:00
r . readInt64 ( )
2016-02-28 15:59:33 -09:00
return ""
2015-02-27 22:57:28 -05:00
}
2016-04-04 22:36:43 +03:00
if cap ( r . rdBuf ) < n {
r . rdBuf = make ( [ ] byte , 2 * n )
2016-04-03 18:27:17 +00:00
}
2019-05-08 15:44:49 -04:00
sOffset := r . roOffset
origName , err := r . peek ( n )
2016-04-06 07:11:24 -04:00
if err == bufio . ErrBufferFull {
// Long symbol names are rare but exist. One source is type
// symbols for types with long string forms. See #15104.
origName = make ( [ ] byte , n )
r . readFull ( origName )
} else if err != nil {
2016-05-12 15:13:22 +03:00
log . Fatalf ( "%s: error reading symbol: %v" , r . pn , err )
2016-04-06 07:11:24 -04:00
}
2016-04-03 18:27:17 +00:00
adjName := r . rdBuf [ : 0 ]
2019-04-25 10:35:47 -04:00
nPkgRefs := 0
2016-02-28 15:59:33 -09:00
for {
i := bytes . Index ( origName , emptyPkg )
if i == - 1 {
2019-04-25 10:35:47 -04:00
var s string
if r . roObject != nil && nPkgRefs == 0 {
s = mkROString ( r . roObject [ sOffset : sOffset + int64 ( n ) ] )
} else {
s = string ( append ( adjName , origName ... ) )
}
2016-04-03 18:27:17 +00:00
// Read past the peeked origName, now that we're done with it,
// using the rfBuf (also no longer used) as the scratch space.
// TODO: use bufio.Reader.Discard if available instead?
2016-04-06 07:11:24 -04:00
if err == nil {
r . readFull ( r . rdBuf [ : n ] )
}
2016-04-04 22:36:43 +03:00
r . rdBuf = adjName [ : 0 ] // in case 2*n wasn't enough
2016-04-03 18:27:17 +00:00
return s
2016-02-28 15:59:33 -09:00
}
2019-04-25 10:35:47 -04:00
nPkgRefs ++
2016-02-28 15:59:33 -09:00
adjName = append ( adjName , origName [ : i ] ... )
2019-05-08 15:44:49 -04:00
adjName = append ( adjName , r . pkgpref [ : len ( r . pkgpref ) - 1 ] ... )
2016-02-28 15:59:33 -09:00
adjName = append ( adjName , '.' )
origName = origName [ i + len ( emptyPkg ) : ]
}
}
2016-03-31 18:34:02 +03:00
// Reads the index of a symbol reference and resolves it to a symbol
2017-10-04 17:54:04 -04:00
func ( r * objReader ) readSymIndex ( ) * sym . Symbol {
2016-03-31 18:34:02 +03:00
i := r . readInt ( )
return r . refs [ i ]
2015-02-27 22:57:28 -05:00
}