wasmDwarfExpressions.js (5914B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 /* eslint camelcase: 0*/ 6 /* eslint-disable no-inline-comments */ 7 8 "use strict"; 9 10 class Value { 11 val; 12 13 constructor(val) { 14 this.val = val; 15 } 16 toString() { 17 return `${this.val}`; 18 } 19 } 20 21 const Int32Formatter = { 22 fromAddr(addr) { 23 return `(new DataView(memory0.buffer).getInt32(${addr}, true))`; 24 }, 25 fromValue(value) { 26 return `${value.val}`; 27 }, 28 }; 29 30 const Uint32Formatter = { 31 fromAddr(addr) { 32 return `(new DataView(memory0.buffer).getUint32(${addr}, true))`; 33 }, 34 fromValue(value) { 35 return `(${value.val} >>> 0)`; 36 }, 37 }; 38 39 function createPieceFormatter(bytes) { 40 let getter; 41 switch (bytes) { 42 case 0: 43 case 1: 44 getter = "getUint8"; 45 break; 46 case 2: 47 getter = "getUint16"; 48 break; 49 case 3: 50 case 4: 51 default: 52 // FIXME 64-bit 53 getter = "getUint32"; 54 break; 55 } 56 const mask = (1 << (8 * bytes)) - 1; 57 return { 58 fromAddr(addr) { 59 return `(new DataView(memory0.buffer).${getter}(${addr}, true))`; 60 }, 61 fromValue(value) { 62 return `((${value.val} & ${mask}) >>> 0)`; 63 }, 64 }; 65 } 66 67 // eslint-disable-next-line complexity 68 function toJS(buf, typeFormatter, frame_base = "fp()") { 69 const readU8 = function () { 70 return buf[i++]; 71 }; 72 const readS8 = function () { 73 return (readU8() << 24) >> 24; 74 }; 75 const readU16 = function () { 76 const w = buf[i] | (buf[i + 1] << 8); 77 i += 2; 78 return w; 79 }; 80 const readS16 = function () { 81 return (readU16() << 16) >> 16; 82 }; 83 const readS32 = function () { 84 const w = 85 buf[i] | (buf[i + 1] << 8) | (buf[i + 2] << 16) | (buf[i + 3] << 24); 86 i += 4; 87 return w; 88 }; 89 const readU32 = function () { 90 return readS32() >>> 0; 91 }; 92 const readU = function () { 93 let n = 0, 94 shift = 0, 95 b; 96 while ((b = readU8()) & 0x80) { 97 n |= (b & 0x7f) << shift; 98 shift += 7; 99 } 100 return n | (b << shift); 101 }; 102 const readS = function () { 103 let n = 0, 104 shift = 0, 105 b; 106 while ((b = readU8()) & 0x80) { 107 n |= (b & 0x7f) << shift; 108 shift += 7; 109 } 110 n |= b << shift; 111 shift += 7; 112 return shift > 32 ? (n << (32 - shift)) >> (32 - shift) : n; 113 }; 114 const popValue = function (formatter) { 115 const loc = stack.pop(); 116 if (loc instanceof Value) { 117 return formatter.fromValue(loc); 118 } 119 return formatter.fromAddr(loc); 120 }; 121 let i = 0, 122 a, 123 b; 124 const stack = [frame_base]; 125 while (i < buf.length) { 126 const code = buf[i++]; 127 switch (code) { 128 case 0x03 /* DW_OP_addr */: 129 stack.push(Uint32Formatter.fromAddr(readU32())); 130 break; 131 case 0x08 /* DW_OP_const1u 0x08 1 1-byte constant */: 132 stack.push(readU8()); 133 break; 134 case 0x09 /* DW_OP_const1s 0x09 1 1-byte constant */: 135 stack.push(readS8()); 136 break; 137 case 0x0a /* DW_OP_const2u 0x0a 1 2-byte constant */: 138 stack.push(readU16()); 139 break; 140 case 0x0b /* DW_OP_const2s 0x0b 1 2-byte constant */: 141 stack.push(readS16()); 142 break; 143 case 0x0c /* DW_OP_const2u 0x0a 1 2-byte constant */: 144 stack.push(readU32()); 145 break; 146 case 0x0d /* DW_OP_const2s 0x0b 1 2-byte constant */: 147 stack.push(readS32()); 148 break; 149 case 0x10 /* DW_OP_constu 0x10 1 ULEB128 constant */: 150 stack.push(readU()); 151 break; 152 case 0x11 /* DW_OP_const2s 0x0b 1 2-byte constant */: 153 stack.push(readS()); 154 break; 155 156 case 0x1c /* DW_OP_minus */: 157 b = stack.pop(); 158 a = stack.pop(); 159 stack.push(`${a} - ${b}`); 160 break; 161 162 case 0x22 /* DW_OP_plus */: 163 b = stack.pop(); 164 a = stack.pop(); 165 stack.push(`${a} + ${b}`); 166 break; 167 168 case 0x23 /* DW_OP_plus_uconst */: 169 b = readU(); 170 a = stack.pop(); 171 stack.push(`${a} + ${b}`); 172 break; 173 174 case 0x30 /* DW_OP_lit0 */: 175 case 0x31: 176 case 0x32: 177 case 0x33: 178 case 0x34: 179 case 0x35: 180 case 0x36: 181 case 0x37: 182 case 0x38: 183 case 0x39: 184 case 0x3a: 185 case 0x3b: 186 case 0x3c: 187 case 0x3d: 188 case 0x3e: 189 case 0x3f: 190 case 0x40: 191 case 0x41: 192 case 0x42: 193 case 0x43: 194 case 0x44: 195 case 0x45: 196 case 0x46: 197 case 0x47: 198 case 0x48: 199 case 0x49: 200 case 0x4a: 201 case 0x4b: 202 case 0x4c: 203 case 0x4d: 204 case 0x4e: 205 case 0x4f: 206 stack.push(`${code - 0x30}`); 207 break; 208 209 case 0x93 /* DW_OP_piece */: { 210 a = readU(); 211 const formatter = createPieceFormatter(a); 212 stack.push(popValue(formatter)); 213 break; 214 } 215 216 case 0x9f /* DW_OP_stack_value */: 217 stack.push(new Value(stack.pop())); 218 break; 219 220 case 0xf6 /* WASM ext (old, FIXME phase out) */: 221 case 0xed /* WASM ext */: 222 b = readU(); 223 a = readS(); 224 switch (b) { 225 case 0: 226 stack.push(`var${a}`); 227 break; 228 case 1: 229 stack.push(`global${a}`); 230 break; 231 default: 232 stack.push(`ti${b}(${a})`); 233 break; 234 } 235 break; 236 237 default: 238 // Unknown encoding, baling out 239 return null; 240 } 241 } 242 // FIXME use real DWARF type information 243 return popValue(typeFormatter); 244 } 245 246 function decodeExpr(expr) { 247 if (expr.includes("//")) { 248 expr = expr.slice(0, expr.indexOf("//")).trim(); 249 } 250 const code = new Uint8Array(expr.length >> 1); 251 for (let i = 0; i < code.length; i++) { 252 code[i] = parseInt(expr.substr(i << 1, 2), 16); 253 } 254 const typeFormatter = Int32Formatter; 255 return toJS(code, typeFormatter) || `dwarf("${expr}")`; 256 } 257 258 module.exports = { 259 decodeExpr, 260 };