// 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 } symtab, _ = loadXCOFFTable(f.xcoff, "runtime.symtab", "runtime.esymtab") // ignore error, this symbol is not useful anyway 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() }