github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/objfile/xcoff.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Parsing of XCOFF executable (AIX)
     6  
     7  package objfile
     8  
     9  import (
    10  	"debug/dwarf"
    11  	"fmt"
    12  	"io"
    13  	"unicode"
    14  
    15  	"github.com/go-asm/go/xcoff"
    16  )
    17  
    18  type xcoffFile struct {
    19  	xcoff *xcoff.File
    20  }
    21  
    22  func openXcoff(r io.ReaderAt) (rawFile, error) {
    23  	f, err := xcoff.NewFile(r)
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  	return &xcoffFile{f}, nil
    28  }
    29  
    30  func (f *xcoffFile) symbols() ([]Sym, error) {
    31  	var syms []Sym
    32  	for _, s := range f.xcoff.Symbols {
    33  		const (
    34  			N_UNDEF = 0  // An undefined (extern) symbol
    35  			N_ABS   = -1 // An absolute symbol (e_value is a constant, not an address)
    36  			N_DEBUG = -2 // A debugging symbol
    37  		)
    38  		sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
    39  
    40  		switch s.SectionNumber {
    41  		case N_UNDEF:
    42  			sym.Code = 'U'
    43  		case N_ABS:
    44  			sym.Code = 'C'
    45  		case N_DEBUG:
    46  			sym.Code = '?'
    47  		default:
    48  			if s.SectionNumber < 0 || len(f.xcoff.Sections) < int(s.SectionNumber) {
    49  				return nil, fmt.Errorf("invalid section number in symbol table")
    50  			}
    51  			sect := f.xcoff.Sections[s.SectionNumber-1]
    52  
    53  			// debug/xcoff returns an offset in the section not the actual address
    54  			sym.Addr += sect.VirtualAddress
    55  
    56  			if s.AuxCSect.SymbolType&0x3 == xcoff.XTY_LD {
    57  				// The size of a function is contained in the
    58  				// AUX_FCN entry
    59  				sym.Size = s.AuxFcn.Size
    60  			} else {
    61  				sym.Size = s.AuxCSect.Length
    62  			}
    63  
    64  			sym.Size = s.AuxCSect.Length
    65  
    66  			switch sect.Type {
    67  			case xcoff.STYP_TEXT:
    68  				if s.AuxCSect.StorageMappingClass == xcoff.XMC_RO {
    69  					sym.Code = 'R'
    70  				} else {
    71  					sym.Code = 'T'
    72  				}
    73  			case xcoff.STYP_DATA:
    74  				sym.Code = 'D'
    75  			case xcoff.STYP_BSS:
    76  				sym.Code = 'B'
    77  			}
    78  
    79  			if s.StorageClass == xcoff.C_HIDEXT {
    80  				// Local symbol
    81  				sym.Code = unicode.ToLower(sym.Code)
    82  			}
    83  
    84  		}
    85  		syms = append(syms, sym)
    86  	}
    87  
    88  	return syms, nil
    89  }
    90  
    91  func (f *xcoffFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
    92  	if sect := f.xcoff.Section(".text"); sect != nil {
    93  		textStart = sect.VirtualAddress
    94  	}
    95  	if pclntab, err = loadXCOFFTable(f.xcoff, "runtime.pclntab", "runtime.epclntab"); err != nil {
    96  		return 0, nil, nil, err
    97  	}
    98  	symtab, _ = loadXCOFFTable(f.xcoff, "runtime.symtab", "runtime.esymtab") // ignore error, this symbol is not useful anyway
    99  	return textStart, symtab, pclntab, nil
   100  }
   101  
   102  func (f *xcoffFile) text() (textStart uint64, text []byte, err error) {
   103  	sect := f.xcoff.Section(".text")
   104  	if sect == nil {
   105  		return 0, nil, fmt.Errorf("text section not found")
   106  	}
   107  	textStart = sect.VirtualAddress
   108  	text, err = sect.Data()
   109  	return
   110  }
   111  
   112  func findXCOFFSymbol(f *xcoff.File, name string) (*xcoff.Symbol, error) {
   113  	for _, s := range f.Symbols {
   114  		if s.Name != name {
   115  			continue
   116  		}
   117  		if s.SectionNumber <= 0 {
   118  			return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber)
   119  		}
   120  		if len(f.Sections) < int(s.SectionNumber) {
   121  			return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections))
   122  		}
   123  		return s, nil
   124  	}
   125  	return nil, fmt.Errorf("no %s symbol found", name)
   126  }
   127  
   128  func loadXCOFFTable(f *xcoff.File, sname, ename string) ([]byte, error) {
   129  	ssym, err := findXCOFFSymbol(f, sname)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	esym, err := findXCOFFSymbol(f, ename)
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	if ssym.SectionNumber != esym.SectionNumber {
   138  		return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename)
   139  	}
   140  	sect := f.Sections[ssym.SectionNumber-1]
   141  	data, err := sect.Data()
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	return data[ssym.Value:esym.Value], nil
   146  }
   147  
   148  func (f *xcoffFile) goarch() string {
   149  	switch f.xcoff.TargetMachine {
   150  	case xcoff.U802TOCMAGIC:
   151  		return "ppc"
   152  	case xcoff.U64_TOCMAGIC:
   153  		return "ppc64"
   154  	}
   155  	return ""
   156  }
   157  
   158  func (f *xcoffFile) loadAddress() (uint64, error) {
   159  	return 0, fmt.Errorf("unknown load address")
   160  }
   161  
   162  func (f *xcoffFile) dwarf() (*dwarf.Data, error) {
   163  	return f.xcoff.DWARF()
   164  }