cmd/internal/objfile: break out dissassemblers to another package

Currently, cmd/internal/objfile provides dissassembly routines for
various architectures, which depend on dissassemblers from x/arch.
cmd/internal/objfile is imported in tools that need dissassembly
(objdump, pprof) and tools that don't need dissassembly (nm,
addr2line). Adding/improving disassembly support for more
architectures can cause binary size increase, and for some tools
(nm, addr2line) it is not necessary.

This CL breaks out dissassembly routines to a different package,
which is only imported in tools that need dissassembly. Other
tools can depend on cmd/internal/objfile without the disassembly
code from x/arch.

This reduces binary sizes for those tools. On darwin/arm64,

                                 old         new
cmd/addr2line                  4554418     3648882   -20%
cmd/addr2line (-ldflags=-w)    3464626     2641650   -24%
cmd/nm                         4503874     3616722   -20%
cmd/nm (-ldflags=-w)           3430594     2609490   -24%

For #70699.

Change-Id: Ie45d5d5c5500c5f3882e8b3c4e6eb81f0d815292
Reviewed-on: https://go-review.googlesource.com/c/go/+/634916
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Cherry Mui 2024-12-10 12:00:10 -05:00
parent e0c76d95ab
commit 6c25cf1c5f
4 changed files with 28 additions and 22 deletions

View file

@ -2,13 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package objfile
// Package disasm provides disassembly routines.
//
// It is broken out from cmd/internal/objfile so tools that don't need
// disassembling don't need to depend on x/arch disassembler code.
package disasm
import (
"bufio"
"bytes"
"container/list"
"debug/gosym"
"encoding/binary"
"fmt"
"io"
@ -19,6 +22,7 @@ import (
"strings"
"text/tabwriter"
"cmd/internal/objfile"
"cmd/internal/src"
"golang.org/x/arch/arm/armasm"
@ -32,8 +36,8 @@ import (
// Disasm is a disassembler for a given File.
type Disasm struct {
syms []Sym //symbols in file, sorted by address
pcln Liner // pcln table
syms []objfile.Sym // symbols in file, sorted by address
pcln objfile.Liner // pcln table
text []byte // bytes of text segment (actual instructions)
textStart uint64 // start PC of text
textEnd uint64 // end PC of text
@ -42,8 +46,12 @@ type Disasm struct {
byteOrder binary.ByteOrder // byte order for goarch
}
// Disasm returns a disassembler for the file f.
func (e *Entry) Disasm() (*Disasm, error) {
// DisasmForFile returns a disassembler for the file f.
func DisasmForFile(f *objfile.File) (*Disasm, error) {
return disasmForEntry(f.Entries()[0])
}
func disasmForEntry(e *objfile.Entry) (*Disasm, error) {
syms, err := e.Symbols()
if err != nil {
return nil, err
@ -269,7 +277,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, pr
}
// Decode disassembles the text segment range [start, end), calling f for each instruction.
func (d *Disasm) Decode(start, end uint64, relocs []Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) {
func (d *Disasm) Decode(start, end uint64, relocs []objfile.Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) {
if start < d.textStart {
start = d.textStart
}
@ -452,9 +460,3 @@ var byteOrders = map[string]binary.ByteOrder{
"riscv64": binary.LittleEndian,
"s390x": binary.BigEndian,
}
type Liner interface {
// Given a pc, returns the corresponding file, line, and function data.
// If unknown, returns "",0,nil.
PCToLine(uint64) (string, int, *gosym.Func)
}

View file

@ -119,10 +119,6 @@ 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
}
@ -181,3 +177,9 @@ func (e *Entry) LoadAddress() (uint64, error) {
func (e *Entry) DWARF() (*dwarf.Data, error) {
return e.raw.dwarf()
}
type Liner interface {
// Given a pc, returns the corresponding file, line, and function data.
// If unknown, returns "",0,nil.
PCToLine(uint64) (string, int, *gosym.Func)
}

View file

@ -40,6 +40,7 @@ import (
"strconv"
"strings"
"cmd/internal/disasm"
"cmd/internal/objfile"
"cmd/internal/telemetry/counter"
)
@ -82,7 +83,7 @@ func main() {
}
defer f.Close()
dis, err := f.Disasm()
dis, err := disasm.DisasmForFile(f)
if err != nil {
log.Fatalf("disassemble %s: %v", flag.Arg(0), err)
}

View file

@ -24,6 +24,7 @@ import (
"sync"
"time"
"cmd/internal/disasm"
"cmd/internal/objfile"
"cmd/internal/telemetry/counter"
@ -162,7 +163,7 @@ func adjustURL(source string, duration, timeout time.Duration) (string, time.Dur
// (instead of invoking GNU binutils).
type objTool struct {
mu sync.Mutex
disasmCache map[string]*objfile.Disasm
disasmCache map[string]*disasm.Disasm
}
func (*objTool) Open(name string, start, limit, offset uint64, relocationSymbol string) (driver.ObjFile, error) {
@ -202,11 +203,11 @@ func (t *objTool) Disasm(file string, start, end uint64, intelSyntax bool) ([]dr
return asm, nil
}
func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) {
func (t *objTool) cachedDisasm(file string) (*disasm.Disasm, error) {
t.mu.Lock()
defer t.mu.Unlock()
if t.disasmCache == nil {
t.disasmCache = make(map[string]*objfile.Disasm)
t.disasmCache = make(map[string]*disasm.Disasm)
}
d := t.disasmCache[file]
if d != nil {
@ -216,7 +217,7 @@ func (t *objTool) cachedDisasm(file string) (*objfile.Disasm, error) {
if err != nil {
return nil, err
}
d, err = f.Disasm()
d, err = disasm.DisasmForFile(f)
f.Close()
if err != nil {
return nil, err