Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
/* eslint camelcase: 0*/
/* eslint-disable no-inline-comments */
"use strict";
class Value {
val;
constructor(val) {
this.val = val;
}
toString() {
return `${this.val}`;
}
}
const Int32Formatter = {
fromAddr(addr) {
return `(new DataView(memory0.buffer).getInt32(${addr}, true))`;
},
fromValue(value) {
return `${value.val}`;
},
};
const Uint32Formatter = {
fromAddr(addr) {
return `(new DataView(memory0.buffer).getUint32(${addr}, true))`;
},
fromValue(value) {
return `(${value.val} >>> 0)`;
},
};
function createPieceFormatter(bytes) {
let getter;
switch (bytes) {
case 0:
case 1:
getter = "getUint8";
break;
case 2:
getter = "getUint16";
break;
case 3:
case 4:
default:
// FIXME 64-bit
getter = "getUint32";
break;
}
const mask = (1 << (8 * bytes)) - 1;
return {
fromAddr(addr) {
return `(new DataView(memory0.buffer).${getter}(${addr}, true))`;
},
fromValue(value) {
return `((${value.val} & ${mask}) >>> 0)`;
},
};
}
// eslint-disable-next-line complexity
function toJS(buf, typeFormatter, frame_base = "fp()") {
const readU8 = function () {
return buf[i++];
};
const readS8 = function () {
return (readU8() << 24) >> 24;
};
const readU16 = function () {
const w = buf[i] | (buf[i + 1] << 8);
i += 2;
return w;
};
const readS16 = function () {
return (readU16() << 16) >> 16;
};
const readS32 = function () {
const w =
buf[i] | (buf[i + 1] << 8) | (buf[i + 2] << 16) | (buf[i + 3] << 24);
i += 4;
return w;
};
const readU32 = function () {
return readS32() >>> 0;
};
const readU = function () {
let n = 0,
shift = 0,
b;
while ((b = readU8()) & 0x80) {
n |= (b & 0x7f) << shift;
shift += 7;
}
return n | (b << shift);
};
const readS = function () {
let n = 0,
shift = 0,
b;
while ((b = readU8()) & 0x80) {
n |= (b & 0x7f) << shift;
shift += 7;
}
n |= b << shift;
shift += 7;
return shift > 32 ? (n << (32 - shift)) >> (32 - shift) : n;
};
const popValue = function (formatter) {
const loc = stack.pop();
if (loc instanceof Value) {
return formatter.fromValue(loc);
}
return formatter.fromAddr(loc);
};
let i = 0,
a,
b;
const stack = [frame_base];
while (i < buf.length) {
const code = buf[i++];
switch (code) {
case 0x03 /* DW_OP_addr */:
stack.push(Uint32Formatter.fromAddr(readU32()));
break;
case 0x08 /* DW_OP_const1u 0x08 1 1-byte constant */:
stack.push(readU8());
break;
case 0x09 /* DW_OP_const1s 0x09 1 1-byte constant */:
stack.push(readS8());
break;
case 0x0a /* DW_OP_const2u 0x0a 1 2-byte constant */:
stack.push(readU16());
break;
case 0x0b /* DW_OP_const2s 0x0b 1 2-byte constant */:
stack.push(readS16());
break;
case 0x0c /* DW_OP_const2u 0x0a 1 2-byte constant */:
stack.push(readU32());
break;
case 0x0d /* DW_OP_const2s 0x0b 1 2-byte constant */:
stack.push(readS32());
break;
case 0x10 /* DW_OP_constu 0x10 1 ULEB128 constant */:
stack.push(readU());
break;
case 0x11 /* DW_OP_const2s 0x0b 1 2-byte constant */:
stack.push(readS());
break;
case 0x1c /* DW_OP_minus */:
b = stack.pop();
a = stack.pop();
stack.push(`${a} - ${b}`);
break;
case 0x22 /* DW_OP_plus */:
b = stack.pop();
a = stack.pop();
stack.push(`${a} + ${b}`);
break;
case 0x23 /* DW_OP_plus_uconst */:
b = readU();
a = stack.pop();
stack.push(`${a} + ${b}`);
break;
case 0x30 /* DW_OP_lit0 */:
case 0x31:
case 0x32:
case 0x33:
case 0x34:
case 0x35:
case 0x36:
case 0x37:
case 0x38:
case 0x39:
case 0x3a:
case 0x3b:
case 0x3c:
case 0x3d:
case 0x3e:
case 0x3f:
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x45:
case 0x46:
case 0x47:
case 0x48:
case 0x49:
case 0x4a:
case 0x4b:
case 0x4c:
case 0x4d:
case 0x4e:
case 0x4f:
stack.push(`${code - 0x30}`);
break;
case 0x93 /* DW_OP_piece */: {
a = readU();
const formatter = createPieceFormatter(a);
stack.push(popValue(formatter));
break;
}
case 0x9f /* DW_OP_stack_value */:
stack.push(new Value(stack.pop()));
break;
case 0xf6 /* WASM ext (old, FIXME phase out) */:
case 0xed /* WASM ext */:
b = readU();
a = readS();
switch (b) {
case 0:
stack.push(`var${a}`);
break;
case 1:
stack.push(`global${a}`);
break;
default:
stack.push(`ti${b}(${a})`);
break;
}
break;
default:
// Unknown encoding, baling out
return null;
}
}
// FIXME use real DWARF type information
return popValue(typeFormatter);
}
function decodeExpr(expr) {
if (expr.includes("//")) {
expr = expr.slice(0, expr.indexOf("//")).trim();
}
const code = new Uint8Array(expr.length >> 1);
for (let i = 0; i < code.length; i++) {
code[i] = parseInt(expr.substr(i << 1, 2), 16);
}
const typeFormatter = Int32Formatter;
return toJS(code, typeFormatter) || `dwarf("${expr}")`;
}
module.exports = {
decodeExpr,
};