UNPKG

snyk-docker-plugin

Version:
193 lines 7.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LineTable = void 0; // lineTable maps to the Go type https://pkg.go.dev/debug/gosym#LineTable class LineTable { // https://pkg.go.dev/debug/gosym#NewLineTable, but only what we need to read out the files. constructor(b) { // the Go type contains some exported fields, but as we don't require anything, we don't export it. // We only store what we require, so some fields are missing when compared to the Go implementation. this.version = pclnVersion.unknown; this.fileMap = new Map(); // Check header: 4-byte magic, two zeros, pc quantum, pointer size. if (b.length < 16 || b[4] !== 0 || b[5] !== 0 || // pc quantum (b[6] !== 1 && b[6] !== 2 && b[6] !== 4) || // pointer size (b[7] !== 4 && b[7] !== 8)) { throw new Error("unknown header format"); } // determine the endianness and the PCLN Table version const leMagic = b.readUInt32LE(0); const beMagic = b.readUInt32BE(0); if (leMagic === LineTable.go12magic) { this.binary = littleEndian; this.version = pclnVersion.v12; } else if (beMagic === LineTable.go12magic) { this.binary = bigEndian; this.version = pclnVersion.v12; } else if (leMagic === LineTable.go116magic) { this.binary = littleEndian; this.version = pclnVersion.v116; } else if (beMagic === LineTable.go116magic) { this.binary = bigEndian; this.version = pclnVersion.v116; } else if (leMagic === LineTable.go118magic) { this.binary = littleEndian; this.version = pclnVersion.v118; } else if (beMagic === LineTable.go118magic) { this.binary = bigEndian; this.version = pclnVersion.v118; } else if (beMagic === LineTable.go120magic) { this.binary = bigEndian; this.version = pclnVersion.v120; } else if (leMagic === LineTable.go120magic) { this.binary = littleEndian; this.version = pclnVersion.v118; } else { throw new Error(`unknown / unsupported Go version`); } this.ptrsize = b[7]; const uintptr = (b) => { if (this.ptrsize === 4) { return this.binary.Uint32(b); } return this.binary.Uint64(b); }; const offset = (word) => { return uintptr(b.slice(8 + word * this.ptrsize)); }; const data = (word) => { return b.slice(Number(offset(word))); // TODO: int conversion? }; switch (this.version) { case pclnVersion.v118: case pclnVersion.v120: this.nfiletab = Number(offset(1)); this.filetab = data(5); this.funcdata = data(7); break; case pclnVersion.v116: this.nfiletab = Number(offset(1)); this.filetab = data(4); this.funcdata = data(6); break; case pclnVersion.v12: const nfunctab = Number(this.uintptr(b.slice(8))); this.funcdata = b; const functab = b.slice(8 + this.ptrsize); const functabsize = (nfunctab * 2 + 1) * this.functabFieldSize(); const fileoff = this.binary.Uint32(functab.slice(functabsize)); this.filetab = b.slice(Number(fileoff)); this.nfiletab = Number(this.binary.Uint32(this.filetab)); break; default: throw new Error("unreachable"); } } // go12MapFiles returns a list of files that have been found in the symbol table. // In the original Go implementation, this function takes a map and object, but // we don't need to construct a map and don't need the object. // https://cs.opensource.google/go/go/+/refs/tags/go1.18.5:src/debug/gosym/pclntab.go;l=669 go12MapFiles() { this.initFileMap(); const files = []; for (const file of Object.keys(this.fileMap)) { files.push(file); } return files; } // uintptr returns the pointer-sized value encoded at b. // The pointer size is dictated by the table being read. uintptr(b) { if (this.ptrsize === 4) { return BigInt(this.binary.Uint32(b)); } return this.binary.Uint64(b); } // functabFieldSize returns the sivze in bytes of a single functab field. // https://cs.opensource.google/go/go/+/refs/tags/go1.18.5:src/debug/gosym/pclntab.go;l=377 functabFieldSize() { if (this.version >= pclnVersion.v118) { return 4; } return this.ptrsize; } // string returns a Go string found at offset. // https://cs.opensource.google/go/go/+/refs/tags/go1.18.5:src/debug/gosym/pclntab.go;l=372 string(offset) { return this.stringFrom(this.funcdata, offset); } // initFileMap initializes the map from file name to file number. // We technically don't need the number, but match Go's implementation 1:1 instead. // https://cs.opensource.google/go/go/+/refs/tags/go1.18.5:src/debug/gosym/pclntab.go;l=641 initFileMap() { if (this.fileMap.size > 0) { return; } const files = new Map(); if (this.version === pclnVersion.v12) { for (let i = 1; i < this.nfiletab; i++) { const fileName = this.string(Number(this.binary.Uint32(this.filetab.slice(4 * i)))); files[fileName] = i; } } else { let pos = 0; for (let i = 0; i < this.nfiletab; i++) { const fileName = this.stringFrom(this.filetab, pos); files[fileName] = pos; pos += fileName.length + 1; } } this.fileMap = files; } // stringFrom returns a Go string found at offset from a position. // https://cs.opensource.google/go/go/+/refs/tags/go1.18.5:src/debug/gosym/pclntab.go;l=361 stringFrom(arr, offset) { const i = arr.slice(offset).indexOf(0); const s = arr.slice(offset, offset + i).toString("ascii"); return s; } } exports.LineTable = LineTable; LineTable.go12magic = 0xfffffffb; LineTable.go116magic = 0xfffffffa; LineTable.go118magic = 0xfffffff0; LineTable.go120magic = 0xfffffff1; var pclnVersion; (function (pclnVersion) { pclnVersion[pclnVersion["unknown"] = 0] = "unknown"; pclnVersion[pclnVersion["v11"] = 1] = "v11"; pclnVersion[pclnVersion["v12"] = 2] = "v12"; pclnVersion[pclnVersion["v116"] = 3] = "v116"; pclnVersion[pclnVersion["v118"] = 4] = "v118"; pclnVersion[pclnVersion["v120"] = 5] = "v120"; })(pclnVersion || (pclnVersion = {})); const bigEndian = { Uint32(b) { return BigInt(b.readUInt32BE(0)); }, Uint64(b) { return b.readBigUInt64BE(0); }, }; const littleEndian = { Uint32(b) { return BigInt(b.readUInt32LE(0)); }, Uint64(b) { return b.readBigUInt64LE(0); }, }; //# sourceMappingURL=pclntab.js.map