2016-03-01 22:57:46 +00:00
|
|
|
// Copyright 2014 The Go Authors. All rights reserved.
|
2014-08-07 12:33:06 -04:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
// Package objfile implements portable access to OS-specific executable files.
|
|
|
|
|
package objfile
|
|
|
|
|
|
|
|
|
|
import (
|
2021-04-29 21:49:15 -04:00
|
|
|
"cmd/internal/archive"
|
2024-09-03 17:46:10 +00:00
|
|
|
"cmp"
|
2016-03-23 17:10:18 -07:00
|
|
|
"debug/dwarf"
|
2014-08-07 12:33:06 -04:00
|
|
|
"debug/gosym"
|
|
|
|
|
"fmt"
|
2017-09-16 15:28:14 +09:00
|
|
|
"io"
|
2014-08-07 12:33:06 -04:00
|
|
|
"os"
|
2024-09-03 17:46:10 +00:00
|
|
|
"slices"
|
2014-08-07 12:33:06 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type rawFile interface {
|
|
|
|
|
symbols() (syms []Sym, err error)
|
|
|
|
|
pcln() (textStart uint64, symtab, pclntab []byte, err error)
|
2014-10-29 18:07:24 -04:00
|
|
|
text() (textStart uint64, text []byte, err error)
|
|
|
|
|
goarch() string
|
2016-05-27 16:03:44 -07:00
|
|
|
loadAddress() (uint64, error)
|
2016-03-23 17:10:18 -07:00
|
|
|
dwarf() (*dwarf.Data, error)
|
2014-08-07 12:33:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A File is an opened executable file.
|
|
|
|
|
type File struct {
|
2017-09-16 15:28:14 +09:00
|
|
|
r *os.File
|
|
|
|
|
entries []*Entry
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Entry struct {
|
|
|
|
|
name string
|
|
|
|
|
raw rawFile
|
2014-08-07 12:33:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A Sym is a symbol defined in an executable file.
|
|
|
|
|
type Sym struct {
|
2016-07-02 17:19:25 -07:00
|
|
|
Name string // symbol name
|
|
|
|
|
Addr uint64 // virtual address of symbol
|
|
|
|
|
Size int64 // size in bytes
|
|
|
|
|
Code rune // nm code (T for text, D for data, and so on)
|
|
|
|
|
Type string // XXX?
|
|
|
|
|
Relocs []Reloc // in increasing Addr order
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Reloc struct {
|
|
|
|
|
Addr uint64 // Address of first byte that reloc applies to.
|
|
|
|
|
Size uint64 // Number of bytes
|
|
|
|
|
Stringer RelocStringer
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type RelocStringer interface {
|
|
|
|
|
// insnOffset is the offset of the instruction containing the relocation
|
|
|
|
|
// from the start of the symbol containing the relocation.
|
|
|
|
|
String(insnOffset uint64) string
|
2014-08-07 12:33:06 -04:00
|
|
|
}
|
|
|
|
|
|
2017-09-16 15:28:14 +09:00
|
|
|
var openers = []func(io.ReaderAt) (rawFile, error){
|
2014-08-07 12:33:06 -04:00
|
|
|
openElf,
|
|
|
|
|
openMacho,
|
|
|
|
|
openPE,
|
|
|
|
|
openPlan9,
|
2018-10-22 17:00:37 +02:00
|
|
|
openXcoff,
|
2014-08-07 12:33:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Open opens the named file.
|
|
|
|
|
// The caller must call f.Close when the file is no longer needed.
|
|
|
|
|
func Open(name string) (*File, error) {
|
|
|
|
|
r, err := os.Open(name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2017-09-16 15:28:14 +09:00
|
|
|
if f, err := openGoFile(r); err == nil {
|
|
|
|
|
return f, nil
|
2021-04-29 21:49:15 -04:00
|
|
|
} else if _, ok := err.(archive.ErrGoObjOtherVersion); ok {
|
|
|
|
|
return nil, fmt.Errorf("open %s: %v", name, err)
|
2017-09-16 15:28:14 +09:00
|
|
|
}
|
2014-08-07 12:33:06 -04:00
|
|
|
for _, try := range openers {
|
|
|
|
|
if raw, err := try(r); err == nil {
|
2019-09-09 09:00:53 +03:00
|
|
|
return &File{r, []*Entry{{raw: raw}}}, nil
|
2014-08-07 12:33:06 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
r.Close()
|
|
|
|
|
return nil, fmt.Errorf("open %s: unrecognized object file", name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *File) Close() error {
|
|
|
|
|
return f.r.Close()
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-16 15:28:14 +09:00
|
|
|
func (f *File) Entries() []*Entry {
|
|
|
|
|
return f.entries
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-07 12:33:06 -04:00
|
|
|
func (f *File) Symbols() ([]Sym, error) {
|
2017-09-16 15:28:14 +09:00
|
|
|
return f.entries[0].Symbols()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *File) PCLineTable() (Liner, error) {
|
|
|
|
|
return f.entries[0].PCLineTable()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *File) Text() (uint64, []byte, error) {
|
|
|
|
|
return f.entries[0].Text()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *File) GOARCH() string {
|
|
|
|
|
return f.entries[0].GOARCH()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *File) LoadAddress() (uint64, error) {
|
|
|
|
|
return f.entries[0].LoadAddress()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *File) DWARF() (*dwarf.Data, error) {
|
|
|
|
|
return f.entries[0].DWARF()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *File) Disasm() (*Disasm, error) {
|
|
|
|
|
return f.entries[0].Disasm()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *Entry) Name() string {
|
|
|
|
|
return e.name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *Entry) Symbols() ([]Sym, error) {
|
|
|
|
|
syms, err := e.raw.symbols()
|
2014-11-06 19:56:55 -05:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2024-09-03 17:46:10 +00:00
|
|
|
slices.SortFunc(syms, func(a, b Sym) int {
|
|
|
|
|
return cmp.Compare(a.Addr, b.Addr)
|
|
|
|
|
})
|
2014-11-06 19:56:55 -05:00
|
|
|
return syms, nil
|
2014-08-07 12:33:06 -04:00
|
|
|
}
|
|
|
|
|
|
2017-09-16 15:28:14 +09:00
|
|
|
func (e *Entry) PCLineTable() (Liner, error) {
|
2016-07-02 17:19:25 -07:00
|
|
|
// If the raw file implements Liner directly, use that.
|
|
|
|
|
// Currently, only Go intermediate objects and archives (goobj) use this path.
|
2017-09-16 15:28:14 +09:00
|
|
|
if pcln, ok := e.raw.(Liner); ok {
|
2016-07-02 17:19:25 -07:00
|
|
|
return pcln, nil
|
|
|
|
|
}
|
|
|
|
|
// Otherwise, read the pcln tables and build a Liner out of that.
|
2017-09-16 15:28:14 +09:00
|
|
|
textStart, symtab, pclntab, err := e.raw.pcln()
|
2014-08-07 12:33:06 -04:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
cmd/internal/objfile, debug/gosym: use the address of runtime.text as textStart
Tools like objdump uses the pcln table to find the line number of
a given PC. For a PIE binary, at least in some cases such as on
macOS 12 with ld64-711, the table contains unrelocated address,
which does not match the address in the symbol table, causing the
lookup to fail.
In Go 1.18 the pcln table is essentually position independent,
except the start PC. Instead of reading the static content from
the table, use the PC of runtime.text from the symbol table.
While here, change the type of textStart to uint64. What matters
here is the word size of the target program, not the host, so it
shouldn't be uintptr.
Fixes #49700.
Change-Id: I517d79be7ba02dd4dd0275e75a11a136b08d76cd
Reviewed-on: https://go-review.googlesource.com/c/go/+/366695
Trust: Cherry Mui <cherryyz@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
2021-11-23 18:03:47 -05:00
|
|
|
syms, err := e.raw.symbols()
|
|
|
|
|
if err == nil {
|
|
|
|
|
for _, s := range syms {
|
|
|
|
|
if s.Name == "runtime.text" {
|
|
|
|
|
textStart = s.Addr
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-08-07 12:33:06 -04:00
|
|
|
return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart))
|
|
|
|
|
}
|
2014-10-29 18:07:24 -04:00
|
|
|
|
2017-09-16 15:28:14 +09:00
|
|
|
func (e *Entry) Text() (uint64, []byte, error) {
|
|
|
|
|
return e.raw.text()
|
2014-10-29 18:07:24 -04:00
|
|
|
}
|
|
|
|
|
|
2017-09-16 15:28:14 +09:00
|
|
|
func (e *Entry) GOARCH() string {
|
|
|
|
|
return e.raw.goarch()
|
2014-10-29 18:07:24 -04:00
|
|
|
}
|
2016-03-23 17:10:18 -07:00
|
|
|
|
2016-05-27 16:03:44 -07:00
|
|
|
// LoadAddress returns the expected load address of the file.
|
|
|
|
|
// This differs from the actual load address for a position-independent
|
|
|
|
|
// executable.
|
2017-09-16 15:28:14 +09:00
|
|
|
func (e *Entry) LoadAddress() (uint64, error) {
|
|
|
|
|
return e.raw.loadAddress()
|
2016-05-27 16:03:44 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-23 17:10:18 -07:00
|
|
|
// DWARF returns DWARF debug data for the file, if any.
|
|
|
|
|
// This is for cmd/pprof to locate cgo functions.
|
2017-09-16 15:28:14 +09:00
|
|
|
func (e *Entry) DWARF() (*dwarf.Data, error) {
|
|
|
|
|
return e.raw.dwarf()
|
2016-03-23 17:10:18 -07:00
|
|
|
}
|