| | |
| | |
| | |
| |
|
| | |
| | package objfile |
| |
|
| | import ( |
| | "cmd/internal/archive" |
| | "cmp" |
| | "debug/dwarf" |
| | "debug/gosym" |
| | "fmt" |
| | "io" |
| | "os" |
| | "slices" |
| | ) |
| |
|
| | type rawFile interface { |
| | symbols() (syms []Sym, err error) |
| | pcln() (textStart uint64, pclntab []byte, err error) |
| | text() (textStart uint64, text []byte, err error) |
| | goarch() string |
| | loadAddress() (uint64, error) |
| | dwarf() (*dwarf.Data, error) |
| | } |
| |
|
| | |
| | type File struct { |
| | r *os.File |
| | entries []*Entry |
| | } |
| |
|
| | type Entry struct { |
| | name string |
| | raw rawFile |
| | } |
| |
|
| | |
| | type Sym struct { |
| | Name string |
| | Addr uint64 |
| | Size int64 |
| | Code rune |
| | Type string |
| | Relocs []Reloc |
| | } |
| |
|
| | type Reloc struct { |
| | Addr uint64 |
| | Size uint64 |
| | Stringer RelocStringer |
| | } |
| |
|
| | type RelocStringer interface { |
| | |
| | |
| | String(insnOffset uint64) string |
| | } |
| |
|
| | var openers = []func(io.ReaderAt) (rawFile, error){ |
| | openElf, |
| | openMacho, |
| | openPE, |
| | openPlan9, |
| | openXcoff, |
| | } |
| |
|
| | |
| | |
| | func Open(name string) (*File, error) { |
| | r, err := os.Open(name) |
| | if err != nil { |
| | return nil, err |
| | } |
| | if f, err := openGoFile(r); err == nil { |
| | return f, nil |
| | } else if _, ok := err.(archive.ErrGoObjOtherVersion); ok { |
| | return nil, fmt.Errorf("open %s: %v", name, err) |
| | } |
| | for _, try := range openers { |
| | if raw, err := try(r); err == nil { |
| | return &File{r, []*Entry{{raw: raw}}}, nil |
| | } |
| | } |
| | r.Close() |
| | return nil, fmt.Errorf("open %s: unrecognized object file", name) |
| | } |
| |
|
| | func (f *File) Close() error { |
| | return f.r.Close() |
| | } |
| |
|
| | func (f *File) Entries() []*Entry { |
| | return f.entries |
| | } |
| |
|
| | func (f *File) Symbols() ([]Sym, error) { |
| | 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 (e *Entry) Name() string { |
| | return e.name |
| | } |
| |
|
| | func (e *Entry) Symbols() ([]Sym, error) { |
| | syms, err := e.raw.symbols() |
| | if err != nil { |
| | return nil, err |
| | } |
| | slices.SortFunc(syms, func(a, b Sym) int { |
| | return cmp.Compare(a.Addr, b.Addr) |
| | }) |
| | return syms, nil |
| | } |
| |
|
| | func (e *Entry) PCLineTable() (Liner, error) { |
| | |
| | |
| | if pcln, ok := e.raw.(Liner); ok { |
| | return pcln, nil |
| | } |
| | |
| | textStart, pclntab, err := e.raw.pcln() |
| | if err != nil { |
| | return nil, err |
| | } |
| | syms, err := e.raw.symbols() |
| | if err == nil { |
| | for _, s := range syms { |
| | if s.Name == "runtime.text" { |
| | textStart = s.Addr |
| | break |
| | } |
| | } |
| | } |
| | return gosym.NewTable(nil, gosym.NewLineTable(pclntab, textStart)) |
| | } |
| |
|
| | func (e *Entry) Text() (uint64, []byte, error) { |
| | return e.raw.text() |
| | } |
| |
|
| | func (e *Entry) GOARCH() string { |
| | return e.raw.goarch() |
| | } |
| |
|
| | |
| | |
| | |
| | func (e *Entry) LoadAddress() (uint64, error) { |
| | return e.raw.loadAddress() |
| | } |
| |
|
| | |
| | |
| | func (e *Entry) DWARF() (*dwarf.Data, error) { |
| | return e.raw.dwarf() |
| | } |
| |
|
| | type Liner interface { |
| | |
| | |
| | PCToLine(uint64) (string, int, *gosym.Func) |
| | } |
| |
|