mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.link] cmd/link: move more error handling into loader
Move the guts of ctxt.Errorf into loader.Loader, so that we can make calls to it from functions that have a "*loader.Loader" available but not a "ctxt *Link". This is needed to start converting hooks like "adddynrel" in the arch-specific portions of the linker to use loader APIs. Change-Id: Ieedd4583b66504be0e77d7f3fbadafe0d2307a69 Reviewed-on: https://go-review.googlesource.com/c/go/+/229497 Run-TryBot: Than McIntosh <thanm@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Jeremy Faller <jeremy@golang.org>
This commit is contained in:
parent
442fd182fb
commit
3d1007d28e
6 changed files with 70 additions and 42 deletions
|
|
@ -7,8 +7,6 @@ import (
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
"cmd/link/internal/loader"
|
"cmd/link/internal/loader"
|
||||||
"cmd/link/internal/sym"
|
"cmd/link/internal/sym"
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -22,6 +20,7 @@ type symNameFn func(s loader.Sym) string
|
||||||
|
|
||||||
// ErrorReporter is used to make error reporting thread safe.
|
// ErrorReporter is used to make error reporting thread safe.
|
||||||
type ErrorReporter struct {
|
type ErrorReporter struct {
|
||||||
|
loader.ErrorReporter
|
||||||
unresOnce sync.Once
|
unresOnce sync.Once
|
||||||
unresSyms map[unresolvedSymKey]bool
|
unresSyms map[unresolvedSymKey]bool
|
||||||
unresMutex sync.Mutex
|
unresMutex sync.Mutex
|
||||||
|
|
@ -65,23 +64,3 @@ func (reporter *ErrorReporter) errorUnresolved(s *sym.Symbol, r *sym.Reloc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Errorf method logs an error message.
|
|
||||||
//
|
|
||||||
// If more than 20 errors have been printed, exit with an error.
|
|
||||||
//
|
|
||||||
// Logging an error means that on exit cmd/link will delete any
|
|
||||||
// output file and return a non-zero error code.
|
|
||||||
// TODO: consolidate the various different versions of Errorf (
|
|
||||||
// function, Link method, and ErrorReporter method).
|
|
||||||
func (reporter *ErrorReporter) Errorf(s loader.Sym, format string, args ...interface{}) {
|
|
||||||
if s != 0 && reporter.SymName != nil {
|
|
||||||
sn := reporter.SymName(s)
|
|
||||||
format = sn + ": " + format
|
|
||||||
} else {
|
|
||||||
format = fmt.Sprintf("sym %d: %s", s, format)
|
|
||||||
}
|
|
||||||
format += "\n"
|
|
||||||
fmt.Fprintf(os.Stderr, format, args...)
|
|
||||||
afterErrorAction()
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -503,7 +503,7 @@ func (ctxt *Link) loadlib() {
|
||||||
default:
|
default:
|
||||||
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
|
log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
|
||||||
}
|
}
|
||||||
ctxt.loader = loader.NewLoader(flags, elfsetstring)
|
ctxt.loader = loader.NewLoader(flags, elfsetstring, &ctxt.ErrorReporter.ErrorReporter)
|
||||||
ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
|
ctxt.ErrorReporter.SymName = func(s loader.Sym) string {
|
||||||
return ctxt.loader.SymName(s)
|
return ctxt.loader.SymName(s)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,19 +34,22 @@ package ld
|
||||||
import (
|
import (
|
||||||
"cmd/internal/objabi"
|
"cmd/internal/objabi"
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
|
"cmd/link/internal/loader"
|
||||||
"cmd/link/internal/sym"
|
"cmd/link/internal/sym"
|
||||||
"log"
|
"log"
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func linknew(arch *sys.Arch) *Link {
|
func linknew(arch *sys.Arch) *Link {
|
||||||
|
ler := loader.ErrorReporter{AfterErrorAction: afterErrorAction}
|
||||||
ctxt := &Link{
|
ctxt := &Link{
|
||||||
Target: Target{Arch: arch},
|
Target: Target{Arch: arch},
|
||||||
Syms: sym.NewSymbols(),
|
Syms: sym.NewSymbols(),
|
||||||
outSem: make(chan int, 2*runtime.GOMAXPROCS(0)),
|
outSem: make(chan int, 2*runtime.GOMAXPROCS(0)),
|
||||||
Out: NewOutBuf(arch),
|
Out: NewOutBuf(arch),
|
||||||
LibraryByPkg: make(map[string]*sym.Library),
|
LibraryByPkg: make(map[string]*sym.Library),
|
||||||
numelfsym: 1,
|
numelfsym: 1,
|
||||||
|
ErrorReporter: ErrorReporter{ErrorReporter: ler},
|
||||||
}
|
}
|
||||||
|
|
||||||
if objabi.GOARCH != arch.Name {
|
if objabi.GOARCH != arch.Name {
|
||||||
|
|
|
||||||
|
|
@ -73,12 +73,12 @@ func Errorf(s *sym.Symbol, format string, args ...interface{}) {
|
||||||
// Logging an error means that on exit cmd/link will delete any
|
// Logging an error means that on exit cmd/link will delete any
|
||||||
// output file and return a non-zero error code.
|
// output file and return a non-zero error code.
|
||||||
func (ctxt *Link) Errorf(s loader.Sym, format string, args ...interface{}) {
|
func (ctxt *Link) Errorf(s loader.Sym, format string, args ...interface{}) {
|
||||||
if s != 0 && ctxt.loader != nil {
|
if ctxt.loader != nil {
|
||||||
sn := ctxt.loader.SymName(s)
|
ctxt.loader.Errorf(s, format, args)
|
||||||
format = sn + ": " + format
|
return
|
||||||
} else {
|
|
||||||
format = fmt.Sprintf("sym %d: %s", s, format)
|
|
||||||
}
|
}
|
||||||
|
// Note: this is not expected to happen very often.
|
||||||
|
format = fmt.Sprintf("sym %d: %s", s, format)
|
||||||
format += "\n"
|
format += "\n"
|
||||||
fmt.Fprintf(os.Stderr, format, args...)
|
fmt.Fprintf(os.Stderr, format, args...)
|
||||||
afterErrorAction()
|
afterErrorAction()
|
||||||
|
|
|
||||||
|
|
@ -270,6 +270,8 @@ type Loader struct {
|
||||||
|
|
||||||
elfsetstring elfsetstringFunc
|
elfsetstring elfsetstringFunc
|
||||||
|
|
||||||
|
errorReporter *ErrorReporter
|
||||||
|
|
||||||
SymLookup func(name string, ver int) *sym.Symbol
|
SymLookup func(name string, ver int) *sym.Symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,9 +303,9 @@ const (
|
||||||
FlagStrictDups = 1 << iota
|
FlagStrictDups = 1 << iota
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
|
func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorReporter) *Loader {
|
||||||
nbuiltin := goobj2.NBuiltin()
|
nbuiltin := goobj2.NBuiltin()
|
||||||
return &Loader{
|
ldr := &Loader{
|
||||||
start: make(map[*oReader]Sym),
|
start: make(map[*oReader]Sym),
|
||||||
objs: []objIdx{{}}, // reserve index 0 for nil symbol
|
objs: []objIdx{{}}, // reserve index 0 for nil symbol
|
||||||
objSyms: []objSym{{}}, // reserve index 0 for nil symbol
|
objSyms: []objSym{{}}, // reserve index 0 for nil symbol
|
||||||
|
|
@ -332,8 +334,11 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc) *Loader {
|
||||||
builtinSyms: make([]Sym, nbuiltin),
|
builtinSyms: make([]Sym, nbuiltin),
|
||||||
flags: flags,
|
flags: flags,
|
||||||
elfsetstring: elfsetstring,
|
elfsetstring: elfsetstring,
|
||||||
|
errorReporter: reporter,
|
||||||
sects: []*sym.Section{nil}, // reserve index 0 for nil section
|
sects: []*sym.Section{nil}, // reserve index 0 for nil section
|
||||||
}
|
}
|
||||||
|
reporter.ldr = ldr
|
||||||
|
return ldr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add object file r, return the start index.
|
// Add object file r, return the start index.
|
||||||
|
|
@ -2754,6 +2759,42 @@ func (l *Loader) AssignTextSymbolOrder(libs []*sym.Library, intlibs []bool, exts
|
||||||
return textp2
|
return textp2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrorReporter is a helper class for reporting errors.
|
||||||
|
type ErrorReporter struct {
|
||||||
|
ldr *Loader
|
||||||
|
AfterErrorAction func()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf method logs an error message.
|
||||||
|
//
|
||||||
|
// After each error, the error actions function will be invoked; this
|
||||||
|
// will either terminate the link immediately (if -h option given)
|
||||||
|
// or it will keep a count and exit if more than 20 errors have been printed.
|
||||||
|
//
|
||||||
|
// Logging an error means that on exit cmd/link will delete any
|
||||||
|
// output file and return a non-zero error code.
|
||||||
|
//
|
||||||
|
func (reporter *ErrorReporter) Errorf(s Sym, format string, args ...interface{}) {
|
||||||
|
if s != 0 && reporter.ldr.SymName(s) != "" {
|
||||||
|
format = reporter.ldr.SymName(s) + ": " + format
|
||||||
|
} else {
|
||||||
|
format = fmt.Sprintf("sym %d: %s", s, format)
|
||||||
|
}
|
||||||
|
format += "\n"
|
||||||
|
fmt.Fprintf(os.Stderr, format, args...)
|
||||||
|
reporter.AfterErrorAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetErrorReporter returns the loader's associated error reporter.
|
||||||
|
func (l *Loader) GetErrorReporter() *ErrorReporter {
|
||||||
|
return l.errorReporter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf method logs an error message. See ErrorReporter.Errorf for details.
|
||||||
|
func (l *Loader) Errorf(s Sym, format string, args ...interface{}) {
|
||||||
|
l.errorReporter.Errorf(s, format, args)
|
||||||
|
}
|
||||||
|
|
||||||
// For debugging.
|
// For debugging.
|
||||||
func (l *Loader) Dump() {
|
func (l *Loader) Dump() {
|
||||||
fmt.Println("objs")
|
fmt.Println("objs")
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,16 @@ func addDummyObjSym(t *testing.T, ldr *Loader, or *oReader, name string) Sym {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddMaterializedSymbol(t *testing.T) {
|
func mkLoader() *Loader {
|
||||||
edummy := func(s *sym.Symbol, str string, off int) {}
|
edummy := func(s *sym.Symbol, str string, off int) {}
|
||||||
ldr := NewLoader(0, edummy)
|
er := ErrorReporter{}
|
||||||
|
ldr := NewLoader(0, edummy, &er)
|
||||||
|
er.ldr = ldr
|
||||||
|
return ldr
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddMaterializedSymbol(t *testing.T) {
|
||||||
|
ldr := mkLoader()
|
||||||
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
||||||
or := &dummyOreader
|
or := &dummyOreader
|
||||||
|
|
||||||
|
|
@ -229,8 +236,7 @@ func sameRelocSlice(s1 *Relocs, s2 []Reloc) bool {
|
||||||
type addFunc func(l *Loader, s Sym, s2 Sym) Sym
|
type addFunc func(l *Loader, s Sym, s2 Sym) Sym
|
||||||
|
|
||||||
func TestAddDataMethods(t *testing.T) {
|
func TestAddDataMethods(t *testing.T) {
|
||||||
edummy := func(s *sym.Symbol, str string, off int) {}
|
ldr := mkLoader()
|
||||||
ldr := NewLoader(0, edummy)
|
|
||||||
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
||||||
or := &dummyOreader
|
or := &dummyOreader
|
||||||
|
|
||||||
|
|
@ -352,8 +358,7 @@ func TestAddDataMethods(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOuterSub(t *testing.T) {
|
func TestOuterSub(t *testing.T) {
|
||||||
edummy := func(s *sym.Symbol, str string, off int) {}
|
ldr := mkLoader()
|
||||||
ldr := NewLoader(0, edummy)
|
|
||||||
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
dummyOreader := oReader{version: -1, syms: make([]Sym, 100)}
|
||||||
or := &dummyOreader
|
or := &dummyOreader
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue