@indutny/breakpad
Version:
Fast symbolication of crash reports using breakpad symbol files
125 lines (124 loc) • 3.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.symbolicateFrames = symbolicateFrames;
var _breakpadParserWasm = require("@indutny/breakpad-parser-wasm");
const DECODER = new TextDecoder();
const ENCODER = new TextEncoder();
const CHUNK_SIZE = 1024 * 1024;
async function symbolicateFrames(stream, frames) {
const matches = frames.map(() => null);
const publicMatches = frames.map(() => null);
const lineWatchers = [];
const files = new Map();
let strBuffer = '';
const onStrValue = value => {
strBuffer += DECODER.decode(value);
};
const onLine = (addr, size, line, fileIndex) => {
let file;
for (let i = 0; i < lineWatchers.length; i += 1) {
const watcher = lineWatchers[i];
if (watcher.offset >= addr && watcher.offset - addr < size) {
watcher.line = line;
file || (file = files.get(fileIndex));
watcher.file = file;
}
}
};
const onFile = index => {
files.set(index, strBuffer);
strBuffer = '';
};
const onFunc = (addr, size, _params) => {
const name = strBuffer;
strBuffer = '';
lineWatchers.length = 0;
for (let i = 0; i < frames.length; i += 1) {
const offset = frames[i];
if (offset < addr || offset - addr >= size) {
continue;
}
const entry = {
offset,
name,
addr,
size,
line: null,
file: null
};
matches[i] = entry;
lineWatchers.push(entry);
}
};
const onPublic = (addr, _params) => {
const name = strBuffer;
strBuffer = '';
for (let i = 0; i < frames.length; i += 1) {
const offset = frames[i];
if (offset < addr) {
continue;
}
const existing = publicMatches[i];
if (existing && existing.addr > addr) {
continue;
}
const entry = {
offset,
name,
addr
};
publicMatches[i] = entry;
}
};
const p = new _breakpadParserWasm.Parser({
onLine,
onFile,
onFunc,
onPublic,
onStrValue
});
for await (const rawChunk of stream) {
let chunk;
if (rawChunk instanceof Uint8Array) {
chunk = rawChunk;
} else if (typeof rawChunk === 'string') {
chunk = ENCODER.encode(rawChunk);
}
for (let i = 0; i < chunk.length; i += CHUNK_SIZE) {
p.parse(chunk.subarray(i, i + CHUNK_SIZE));
}
}
p.finish();
p.free();
return matches.map((match, i) => {
if (match === null) {
const publicMatch = publicMatches[i];
if (publicMatch) {
return {
name: publicMatch.name.trim(),
addr: publicMatch.addr,
size: null,
file: null,
line: null
};
}
return null;
}
const {
name,
addr,
size,
file,
line
} = match;
return {
name: name.trim(),
addr,
size,
file: file !== null && file !== void 0 && file.length ? file.trim() : null,
line
};
});
}