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 }