|  | // 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() | 
|  | } |