| // Copyright 2018 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Parsing of XCOFF executable (AIX) |
| |
| package objfile |
| |
| import ( |
| "debug/dwarf" |
| "fmt" |
| "internal/xcoff" |
| "io" |
| "unicode" |
| ) |
| |
| type xcoffFile struct { |
| xcoff *xcoff.File |
| } |
| |
| func openXcoff(r io.ReaderAt) (rawFile, error) { |
| f, err := xcoff.NewFile(r) |
| if err != nil { |
| return nil, err |
| } |
| return &xcoffFile{f}, nil |
| } |
| |
| func (f *xcoffFile) symbols() ([]Sym, error) { |
| var syms []Sym |
| for _, s := range f.xcoff.Symbols { |
| const ( |
| N_UNDEF = 0 // An undefined (extern) symbol |
| N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) |
| N_DEBUG = -2 // A debugging symbol |
| ) |
| sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'} |
| |
| switch s.SectionNumber { |
| case N_UNDEF: |
| sym.Code = 'U' |
| case N_ABS: |
| sym.Code = 'C' |
| case N_DEBUG: |
| sym.Code = '?' |
| default: |
| if s.SectionNumber < 0 || len(f.xcoff.Sections) < int(s.SectionNumber) { |
| return nil, fmt.Errorf("invalid section number in symbol table") |
| } |
| sect := f.xcoff.Sections[s.SectionNumber-1] |
| |
| // debug/xcoff returns an offset in the section not the actual address |
| sym.Addr += sect.VirtualAddress |
| |
| if s.AuxCSect.SymbolType&0x3 == xcoff.XTY_LD { |
| // The size of a function is contained in the |
| // AUX_FCN entry |
| sym.Size = s.AuxFcn.Size |
| } else { |
| sym.Size = s.AuxCSect.Length |
| } |
| |
| sym.Size = s.AuxCSect.Length |
| |
| switch sect.Type { |
| case xcoff.STYP_TEXT: |
| if s.AuxCSect.StorageMappingClass == xcoff.XMC_RO { |
| sym.Code = 'R' |
| } else { |
| sym.Code = 'T' |
| } |
| case xcoff.STYP_DATA: |
| sym.Code = 'D' |
| case xcoff.STYP_BSS: |
| sym.Code = 'B' |
| } |
| |
| if s.StorageClass == xcoff.C_HIDEXT { |
| // Local symbol |
| sym.Code = unicode.ToLower(sym.Code) |
| } |
| |
| } |
| syms = append(syms, sym) |
| } |
| |
| return syms, nil |
| } |
| |
| func (f *xcoffFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { |
| if sect := f.xcoff.Section(".text"); sect != nil { |
| textStart = sect.VirtualAddress |
| } |
| if pclntab, err = loadXCOFFTable(f.xcoff, "runtime.pclntab", "runtime.epclntab"); err != nil { |
| return 0, nil, nil, err |
| } |
| if symtab, err = loadXCOFFTable(f.xcoff, "runtime.symtab", "runtime.esymtab"); err != nil { |
| return 0, nil, nil, err |
| } |
| return textStart, symtab, pclntab, nil |
| } |
| |
| func (f *xcoffFile) text() (textStart uint64, text []byte, err error) { |
| sect := f.xcoff.Section(".text") |
| if sect == nil { |
| return 0, nil, fmt.Errorf("text section not found") |
| } |
| textStart = sect.VirtualAddress |
| text, err = sect.Data() |
| return |
| } |
| |
| func findXCOFFSymbol(f *xcoff.File, name string) (*xcoff.Symbol, error) { |
| for _, s := range f.Symbols { |
| if s.Name != name { |
| continue |
| } |
| if s.SectionNumber <= 0 { |
| return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) |
| } |
| if len(f.Sections) < int(s.SectionNumber) { |
| return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) |
| } |
| return s, nil |
| } |
| return nil, fmt.Errorf("no %s symbol found", name) |
| } |
| |
| func loadXCOFFTable(f *xcoff.File, sname, ename string) ([]byte, error) { |
| ssym, err := findXCOFFSymbol(f, sname) |
| if err != nil { |
| return nil, err |
| } |
| esym, err := findXCOFFSymbol(f, ename) |
| if err != nil { |
| return nil, err |
| } |
| if ssym.SectionNumber != esym.SectionNumber { |
| return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) |
| } |
| sect := f.Sections[ssym.SectionNumber-1] |
| data, err := sect.Data() |
| if err != nil { |
| return nil, err |
| } |
| return data[ssym.Value:esym.Value], nil |
| } |
| |
| func (f *xcoffFile) goarch() string { |
| switch f.xcoff.TargetMachine { |
| case xcoff.U802TOCMAGIC: |
| return "ppc" |
| case xcoff.U64_TOCMAGIC: |
| return "ppc64" |
| } |
| return "" |
| } |
| |
| func (f *xcoffFile) loadAddress() (uint64, error) { |
| return 0, fmt.Errorf("unknown load address") |
| } |
| |
| func (f *xcoffFile) dwarf() (*dwarf.Data, error) { |
| return f.xcoff.DWARF() |
| } |