github.com/gopherjs/gopherjs@v1.19.0-beta1.0.20240506212314-27071a8796e4/compiler/natives/src/debug/pe/symbol.go (about)

     1  //go:build js
     2  // +build js
     3  
     4  package pe
     5  
     6  import (
     7  	"encoding/binary"
     8  	"fmt"
     9  	"io"
    10  )
    11  
    12  // bytesBufferLite is a simplified bytes.Buffer to avoid
    13  // including `bytes` as a new import into the pe package.
    14  type bytesBufferLite struct {
    15  	data []byte
    16  	off  int
    17  }
    18  
    19  func (buf *bytesBufferLite) Write(p []byte) (int, error) {
    20  	buf.data = append(buf.data, p...)
    21  	return len(p), nil
    22  }
    23  
    24  func (buf *bytesBufferLite) Read(p []byte) (int, error) {
    25  	n := copy(p, buf.data[buf.off:])
    26  	buf.off += n
    27  	return n, nil
    28  }
    29  
    30  func copyToAuxFormat5(sym *COFFSymbol) (*COFFSymbolAuxFormat5, error) {
    31  	buf := &bytesBufferLite{data: make([]byte, 0, 20)}
    32  	if err := binary.Write(buf, binary.LittleEndian, sym); err != nil {
    33  		return nil, err
    34  	}
    35  	aux := &COFFSymbolAuxFormat5{}
    36  	if err := binary.Read(buf, binary.LittleEndian, aux); err != nil {
    37  		return nil, err
    38  	}
    39  	return aux, nil
    40  }
    41  
    42  func copyFromAuxFormat5(aux *COFFSymbolAuxFormat5) (*COFFSymbol, error) {
    43  	buf := &bytesBufferLite{data: make([]byte, 0, 20)}
    44  	if err := binary.Write(buf, binary.LittleEndian, aux); err != nil {
    45  		return nil, err
    46  	}
    47  	sym := &COFFSymbol{}
    48  	if err := binary.Read(buf, binary.LittleEndian, sym); err != nil {
    49  		return nil, err
    50  	}
    51  	return sym, nil
    52  }
    53  
    54  func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) {
    55  	if fh.PointerToSymbolTable == 0 {
    56  		return nil, nil
    57  	}
    58  	if fh.NumberOfSymbols <= 0 {
    59  		return nil, nil
    60  	}
    61  	_, err := r.Seek(int64(fh.PointerToSymbolTable), seekStart)
    62  	if err != nil {
    63  		return nil, fmt.Errorf("fail to seek to symbol table: %v", err)
    64  	}
    65  	syms := make([]COFFSymbol, fh.NumberOfSymbols)
    66  	naux := 0
    67  	for k := range syms {
    68  		if naux == 0 {
    69  			err = binary.Read(r, binary.LittleEndian, &syms[k])
    70  			if err != nil {
    71  				return nil, fmt.Errorf("fail to read symbol table: %v", err)
    72  			}
    73  			naux = int(syms[k].NumberOfAuxSymbols)
    74  		} else {
    75  			naux--
    76  			// The following was reading into one struct with the same memory
    77  			// footprint as another struck. This doesn't work in JS so the
    78  			// `syms` value is left with a bunch of defaults. So replace
    79  			// aux := (*COFFSymbolAuxFormat5)(unsafe.Pointer(&syms[k]))
    80  			// (an in memory remap) with the following read and then copy.
    81  			aux := &COFFSymbolAuxFormat5{}
    82  			err = binary.Read(r, binary.LittleEndian, aux)
    83  			if err != nil {
    84  				return nil, fmt.Errorf("fail to read symbol table: %v", err)
    85  			}
    86  			pesymn, err := copyFromAuxFormat5(aux)
    87  			if err != nil {
    88  				return nil, err
    89  			}
    90  			syms[k] = *pesymn
    91  		}
    92  	}
    93  	if naux != 0 {
    94  		return nil, fmt.Errorf("fail to read symbol table: %d aux symbols unread", naux)
    95  	}
    96  	return syms, nil
    97  }
    98  
    99  func (f *File) COFFSymbolReadSectionDefAux(idx int) (*COFFSymbolAuxFormat5, error) {
   100  	var rv *COFFSymbolAuxFormat5
   101  	if idx < 0 || idx >= len(f.COFFSymbols) {
   102  		return rv, fmt.Errorf("invalid symbol index")
   103  	}
   104  	pesym := &f.COFFSymbols[idx]
   105  	const IMAGE_SYM_CLASS_STATIC = 3
   106  	if pesym.StorageClass != uint8(IMAGE_SYM_CLASS_STATIC) {
   107  		return rv, fmt.Errorf("incorrect symbol storage class")
   108  	}
   109  	if pesym.NumberOfAuxSymbols == 0 || idx+1 >= len(f.COFFSymbols) {
   110  		return rv, fmt.Errorf("aux symbol unavailable")
   111  	}
   112  	pesymn := &f.COFFSymbols[idx+1]
   113  	// The following was reading one struct as another struct with
   114  	// the same memory footprint. This doesn't work in JS so the
   115  	// `rv` value is left with a bunch of `undefined`s. So replace
   116  	// rv = (*COFFSymbolAuxFormat5)(unsafe.Pointer(pesymn))
   117  	// (an in memory remap) with the following copy.
   118  	return copyToAuxFormat5(pesymn)
   119  }