mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/objdump: implement objdump of .o files
Update goobj reader so it can provide all the information necessary to disassemble .o (and .a) files. Grab architecture of .o files from header. .o files have relocations in them. This CL also contains a simple mechanism to disassemble relocations and add relocation info as an extra column in the output. Fixes #13862 Change-Id: I608fd253ff1522ea47f18be650b38d528dae9054 Reviewed-on: https://go-review.googlesource.com/24818 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
873dca4c17
commit
a99f812cba
14 changed files with 187 additions and 42 deletions
|
|
@ -8,7 +8,9 @@ package objfile
|
|||
|
||||
import (
|
||||
"cmd/internal/goobj"
|
||||
"cmd/internal/sys"
|
||||
"debug/dwarf"
|
||||
"debug/gosym"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
|
@ -16,6 +18,7 @@ import (
|
|||
|
||||
type goobjFile struct {
|
||||
goobj *goobj.Package
|
||||
f *os.File // the underlying .o or .a file
|
||||
}
|
||||
|
||||
func openGoobj(r *os.File) (rawFile, error) {
|
||||
|
|
@ -23,7 +26,7 @@ func openGoobj(r *os.File) (rawFile, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &goobjFile{f}, nil
|
||||
return &goobjFile{goobj: f, f: r}, nil
|
||||
}
|
||||
|
||||
func goobjName(id goobj.SymID) string {
|
||||
|
|
@ -55,6 +58,9 @@ func (f *goobjFile) symbols() ([]Sym, error) {
|
|||
if s.Version != 0 {
|
||||
sym.Code += 'a' - 'A'
|
||||
}
|
||||
for i, r := range s.Reloc {
|
||||
sym.Relocs = append(sym.Relocs, Reloc{Addr: uint64(s.Data.Offset) + uint64(r.Offset), Size: uint64(r.Size), Stringer: &s.Reloc[i]})
|
||||
}
|
||||
syms = append(syms, sym)
|
||||
}
|
||||
|
||||
|
|
@ -75,23 +81,68 @@ func (f *goobjFile) symbols() ([]Sym, error) {
|
|||
return syms, nil
|
||||
}
|
||||
|
||||
// pcln does not make sense for Go object files, because each
|
||||
// symbol has its own individual pcln table, so there is no global
|
||||
// space of addresses to map.
|
||||
func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
|
||||
// Should never be called. We implement Liner below, callers
|
||||
// should use that instead.
|
||||
return 0, nil, nil, fmt.Errorf("pcln not available in go object file")
|
||||
}
|
||||
|
||||
// text does not make sense for Go object files, because
|
||||
// each function has a separate section.
|
||||
func (f *goobjFile) text() (textStart uint64, text []byte, err error) {
|
||||
return 0, nil, fmt.Errorf("text not available in go object file")
|
||||
// Find returns the file name, line, and function data for the given pc.
|
||||
// Returns "",0,nil if unknown.
|
||||
// This function implements the Liner interface in preference to pcln() above.
|
||||
func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
|
||||
// TODO: this is really inefficient. Binary search? Memoize last result?
|
||||
var arch *sys.Arch
|
||||
for _, a := range sys.Archs {
|
||||
if a.Name == f.goobj.Arch {
|
||||
arch = a
|
||||
break
|
||||
}
|
||||
}
|
||||
if arch == nil {
|
||||
return "", 0, nil
|
||||
}
|
||||
for _, s := range f.goobj.Syms {
|
||||
if pc < uint64(s.Data.Offset) || pc >= uint64(s.Data.Offset+s.Data.Size) {
|
||||
continue
|
||||
}
|
||||
if s.Func == nil {
|
||||
return "", 0, nil
|
||||
}
|
||||
pcfile := make([]byte, s.Func.PCFile.Size)
|
||||
_, err := f.f.ReadAt(pcfile, s.Func.PCFile.Offset)
|
||||
if err != nil {
|
||||
return "", 0, nil
|
||||
}
|
||||
fileID := gosym.PCValue(pcfile, pc-uint64(s.Data.Offset), arch.MinLC)
|
||||
fileName := s.Func.File[fileID]
|
||||
pcline := make([]byte, s.Func.PCLine.Size)
|
||||
_, err = f.f.ReadAt(pcline, s.Func.PCLine.Offset)
|
||||
if err != nil {
|
||||
return "", 0, nil
|
||||
}
|
||||
line := gosym.PCValue(pcline, pc-uint64(s.Data.Offset), arch.MinLC)
|
||||
// Note: we provide only the name in the Func structure.
|
||||
// We could provide more if needed.
|
||||
return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: s.Name}}
|
||||
}
|
||||
return "", 0, nil
|
||||
}
|
||||
|
||||
// We treat the whole object file as the text section.
|
||||
func (f *goobjFile) text() (textStart uint64, text []byte, err error) {
|
||||
var info os.FileInfo
|
||||
info, err = f.f.Stat()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text = make([]byte, info.Size())
|
||||
_, err = f.f.ReadAt(text, 0)
|
||||
return
|
||||
}
|
||||
|
||||
// goarch makes sense but is not exposed in debug/goobj's API,
|
||||
// and we don't need it yet for any users of internal/objfile.
|
||||
func (f *goobjFile) goarch() string {
|
||||
return "GOARCH unimplemented for debug/goobj files"
|
||||
return f.goobj.Arch
|
||||
}
|
||||
|
||||
func (f *goobjFile) loadAddress() (uint64, error) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue