From 26e2a879bdefafee3bff0a41e1167cbf29b3ab3f Mon Sep 17 00:00:00 2001 From: bloodstalker Date: Tue, 26 Jun 2018 15:06:55 +0430 Subject: first commit --- README.md | 0 dwasm.py | 33 ++ execute.py | 1056 ++++++++++++++++++++++++++++++++++++++++++++++++++ init.py | 415 ++++++++++++++++++++ linker.py | 2 + opcodes.py | 332 ++++++++++++++++ parse.py | 1031 ++++++++++++++++++++++++++++++++++++++++++++++++ run.sh | 3 + section_structs.py | 301 ++++++++++++++ test/injected.wasm | Bin 0 -> 1313 bytes test/linker/.depend | 2 + test/linker/file0.c | 20 + test/linker/file1.c | 25 ++ test/linker/makefile | 44 +++ utils.py | 425 ++++++++++++++++++++ 15 files changed, 3689 insertions(+) create mode 100644 README.md create mode 100755 dwasm.py create mode 100644 execute.py create mode 100644 init.py create mode 100644 linker.py create mode 100644 opcodes.py create mode 100755 parse.py create mode 100755 run.sh create mode 100644 section_structs.py create mode 100644 test/injected.wasm create mode 100644 test/linker/.depend create mode 100644 test/linker/file0.c create mode 100644 test/linker/file1.c create mode 100644 test/linker/makefile create mode 100644 utils.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/dwasm.py b/dwasm.py new file mode 100755 index 0000000..e404dca --- /dev/null +++ b/dwasm.py @@ -0,0 +1,33 @@ +#!/usr/bin/python3 + +import argparse +import code +import readline +import signal +import sys +from parse import Argparser, premain, SigHandler_SIGINT,PythonInterpreter +from utils import ParseFlags + +def getWASMModule(): + module_path = sys.argv[1] + interpreter = PythonInterpreter() + module = interpreter.parse(module_path) + +def main(): + signal.signal(signal.SIGINT, SigHandler_SIGINT) + argparser = Argparser() + if argparser.args.dbg: + try: + premain(argparser) + except Exception as e: + print(e.__doc__) + if e.message: print(e.message) + variables = globals().copy() + variables.update(locals()) + shell = code.InteractiveConsole(variables) + shell.interact(banner="DEVIWASM REPL") + else: + premain(argparser) + +if __name__ == "__main__": + main() diff --git a/execute.py b/execute.py new file mode 100644 index 0000000..40b9042 --- /dev/null +++ b/execute.py @@ -0,0 +1,1056 @@ +from opcodes import * +from utils import Colors, ror, rol +import numpy as np +import math + + +class Label(): + def __init__(self, arity, name): + self.arity = arity + self.name = name + + +class Frame(): + def __init__(self, arity, local_indices, self_ref): + self.arity = arity + self.local_indices = local_indices + self.self_ref = self_ref + + +# takes the machinestate, opcode and operand to run. updates the machinestate +class Execute(): # pragma: no cover + def __init__(self, machinestate): + self.machinestate = machinestate + self.opcodeint = '' + self.immediates = [] + self.op_gas = int() + self.stack_top = [] + + def getOPGas(self): + return self.op_gas + + def chargeGasMem(self, mem_size_page): + factor = 64 + self.op_gas += 64 * mem_size_page + + def chargeGas(self, opcodeint): + if opcodeint != 64: + self.op_gas += 1 + else: + chargeGasMem() + pass + + def getInstruction(self, opcodeint, immediates): + self.opcodeint = opcodeint + dummy = [] + #FIXME-why is it being cast to int? + for i in immediates: + dummy.append(int(i)) + self.immediates = dummy + + def callExecuteMethod(self): + runmethod = self.instructionUnwinder(self.opcodeint, self.immediates, self.machinestate) + #print (repr(hex(self.opcodeint)) + ' ' + repr(self.immediates)) + try: + runmethod(self.opcodeint, self.immediates) + except IndexError: + # trap + print(Colors.red + 'bad stack access.' + Colors.ENDC) + val2 = self.machinestate.Stack_Omni.pop() + + + def instructionUnwinder(self, opcodeint, immediates, machinestate): + self.chargeGas(opcodeint) + + if opcodeint == 0: + return(self.run_unreachable) + elif opcodeint == 1: + return(self.run_nop) + elif opcodeint == 2: + return(self.run_block) + elif opcodeint == 3: + return(self.run_loop) + elif opcodeint == 4: + return(self.run_if) + elif opcodeint == 5: + return(self.run_else) + elif opcodeint == 11: + return(self.run_end) + elif opcodeint == 12: + return(self.run_br) + elif opcodeint == 13: + return(self.run_br_if) + elif opcodeint == 14: + return(self.run_br_table) + elif opcodeint == 15: + return(self.run_return) + elif opcodeint == 16: + return(self.run_call) + elif opcodeint == 17: + return(self.run_call_indirect) + elif opcodeint == 26: + return(self.run_drop) + elif opcodeint == 27: + return(self.run_select) + elif opcodeint == 32: + return(self.run_getlocal) + elif opcodeint == 33: + return(self.run_setlocal) + elif opcodeint == 34: + return(self.run_teelocal) + elif opcodeint == 35: + return(self.run_getglobal) + elif opcodeint == 36: + return(self.run_setglobal) + elif opcodeint >= 40 and opcodeint <= 53: + return(self.run_load) + elif opcodeint >= 54 and opcodeint <= 62: + return(self.run_store) + elif opcodeint == 63: + return(self.run_current_memory) + elif opcodeint == 64: + self.chargeGasMem(immediates[0]) + return(self.run_grow_memory) + elif opcodeint >= 65 and opcodeint <= 68: + return(self.run_const) + elif opcodeint == 69 or opcodeint == 80: + return(self.run_eqz) + elif opcodeint == 70 or opcodeint == 81 or opcodeint == 91 or opcodeint == 97: + return(self.run_eq) + elif opcodeint == 71 or opcodeint == 82 or opcodeint == 92 or opcodeint == 98: + return(self.run_ne) + elif opcodeint == 72 or opcodeint == 83: + return(self.run_lt_s) + elif opcodeint == 73 or opcodeint == 84: + return(self.run_lt_u) + elif opcodeint == 74 or opcodeint == 85: + return(self.run_gt_s) + elif opcodeint == 75 or opcodeint == 86: + return(self.run_gt_u) + elif opcodeint == 76 or opcodeint == 87: + return(self.run_le_s) + elif opcodeint == 77 or opcodeint == 88: + return(self.run_le_u) + elif opcodeint == 78 or opcodeint == 89: + return(self.run_ge_s) + elif opcodeint == 79 or opcodeint == 90: + return(self.run_ge_u) + elif opcodeint == 93 or opcodeint == 99: + return(self.run_lt) + elif opcodeint == 94 or opcodeint == 100: + return(self.run_gt) + elif opcodeint == 95 or opcodeint == 101: + return(self.run_le) + elif opcodeint == 96 or opcodeint == 102: + return(self.run_ge) + elif opcodeint == 103 or opcodeint == 121: + return(self.run_clz) + elif opcodeint == 104 or opcodeint == 122: + return(self.run_ctz) + elif opcodeint == 105 or opcodeint == 123: + return(self.run_popcnt) + elif opcodeint == 106 or opcodeint == 124 or opcodeint == 146 or opcodeint == 160: + return(self.run_add) + elif opcodeint == 107 or opcodeint == 125 or opcodeint == 147 or opcodeint == 161: + return(self.run_sub) + elif opcodeint == 108 or opcodeint == 126 or opcodeint == 148 or opcodeint == 162: + return(self.run_mul) + elif opcodeint == 109 or opcodeint == 127: + return(self.run_div_s) + elif opcodeint == 110 or opcodeint == 128: + return(self.run_div_u) + elif opcodeint == 111 or opcodeint == 129: + return(self.run_rem_s) + elif opcodeint == 112 or opcodeint == 130: + return(self.run_rem_u) + elif opcodeint == 113 or opcodeint == 131: + return(self.run_and) + elif opcodeint == 114 or opcodeint == 132: + return(self.run_or) + elif opcodeint == 115 or opcodeint == 133: + return(self.run_xor) + elif opcodeint == 116 or opcodeint == 134: + return(self.run_shl) + elif opcodeint == 117 or opcodeint == 135: + return(self.run_shr_s) + elif opcodeint == 118 or opcodeint == 136: + return(self.run_shr_u) + elif opcodeint == 119 or opcodeint == 137: + return(self.run_rotl) + elif opcodeint == 120 or opcodeint == 138: + return(self.run_rotr) + elif opcodeint == 139 or opcodeint == 153: + return(self.run_abs) + elif opcodeint == 140 or opcodeint == 154: + return(self.run_neg) + elif opcodeint == 141 or opcodeint == 155: + return(self.run_ceil) + elif opcodeint == 142 or opcodeint == 156: + return(self.run_floor) + elif opcodeint == 143 or opcodeint == 157: + return(self.run_trunc) + elif opcodeint == 144 or opcodeint == 158: + return(self.run_nearest) + elif opcodeint == 145 or opcodeint == 159: + return(self.run_sqrt) + elif opcodeint == 149 or opcodeint == 163: + return(self.run_div) + elif opcodeint == 150 or opcodeint == 164: + return(self.run_min) + elif opcodeint == 151 or opcodeint == 165: + return(self.run_max) + elif opcodeint == 152 or opcodeint == 166: + return(self.run_copysign) + elif opcodeint == 167: + return(self.run_i32wrapi64) + elif opcodeint == 168: + return(self.run_i32trunc_sf32) + elif opcodeint == 169: + return(self.run_i32trunc_uf32) + elif opcodeint == 170: + return(self.run_i32trunc_sf64) + elif opcodeint == 171: + return(self.run_i32trunc_uf64) + elif opcodeint == 172: + return(self.run_i64extend_si32) + elif opcodeint == 173: + return(self.run_i64extend_ui3o) + elif opcodeint == 174: + return(self.run_i64trunc_sf32) + elif opcodeint == 175: + return(self.run_i64trunc_uf32) + elif opcodeint == 176: + return(self.run_i64trunc_sf64) + elif opcodeint == 177: + return(self.run_i64trunc_uf64) + elif opcodeint == 178: + return(self.run_f32convert_si32) + elif opcodeint == 179: + return(self.run_f32convert_ui32) + elif opcodeint == 180: + return(self.run_f32convert_si64) + elif opcodeint == 181: + return(self.run_f32convert_ui64) + elif opcodeint == 182: + return(self.run_f32demotef64) + elif opcodeint == 183: + return(self.run_f64convert_si32) + elif opcodeint == 184: + return(self.run_f64convert_ui32) + elif opcodeint == 185: + return(self.run_f64convert_si64) + elif opcodeint == 186: + return(self.run_f64convert_ui64) + elif opcodeint == 187: + return(self.run_f64promotef32) + elif opcodeint == 188: + return(self.run_i32reinterpretf32) + elif opcodeint == 189: + return(self.run_i64reinterpretf64) + elif opcodeint == 190: + return(self.run_f32reinterpreti32) + elif opcodeint == 191: + return(self.run_f64reinterpreti64) + else: + raise Exception(Colors.red + 'unknown opcode' + Colors.ENDC) + + def run_unreachable(self, opcodeint, immediates): + # trap + raise Exception(Colors.red + "trapped." + Colors.ENDC) + + def run_nop(self, opcodeint, immediates): + # literally do nothing + pass + + def run_block(self, opcodeint, immediates): + self.machinestate.Stack_Label.append(self.machinestate.Stack_Label_Height) + self.machinestate.Stack_Label_Height += 1 + + def run_loop(self, opcodeint, immediates): + # assertion + if not self.machinestate.Stack_Omni: + print(Colors.red + "entered a loop. stack is empty." + Colors.ENDC) + # exit 1 + self.machinestate.Stack_Label.append(self.machinestate.Stack_Label_Height) + self.machinestate.Stack_Label_Height += 1 + val = self.machinestate.Stack_Omni.pop() + if val != 0: + pass + else: + pass + + def run_if(self, opcodeint, immediates): + pass + + def run_else(self, opcodeint, immediates): + pass + + def run_end(self, opcodeint, immediates): + #self.machinestate.Stack_Label.pop() + pass + + def run_br(self, opcodeint, immediates): + if self.machinestate.Stack_Label_Height >= immediates[0] + 1: + print(Colors.red + "label stack does not have enough labels." + Colors.ENDC) + # exit 1 + if len(self.machinestate.Stack_Omni) < 1: + print(Colors.red + "the value stack does not have enough values." + Colors.ENDC) + # exit 1 + val = self.machinestate.Stack_Omni.pop() + label = self.machinestate.Stack_Label.pop() + + def run_br_if(self, opcodeint, immediates): + val = self.machinestate.Stack_Omni.pop() + if val: + pass + else: + self.run_br(dummy, immediates[0]) + + def run_br_table(self, opcodeint, immediates): + pass + + def run_return(self, opcodeint, immediates): + pass + + def run_call(self, opcodeint, immediates): + pass + + def run_call_indirect(self, opcodeint, immediates): + pass + + def run_drop(self, opcodeint, immediates): + self.machinestate.Stack_Omni.pop() + + def run_select(self, opcodeint, immediates): + pass + + def run_getlocal(self, opcodeint, immediates): + local = self.machinestate.Index_Space_Locals[int(immediates[0])] + self.machinestate.Stack_Omni.append(local) + + def run_setlocal(self, opcodeint, immediates): + self.machinestate.Index_Space_Locals[int(immediates[0])] = self.machinestate.Stack_Omni.pop() + + def run_teelocal(self, dummy, immediates): + # @DEVI-we dont pop and push + self.machinestate.Index_Space_Locals[int(immediates[0])] = self.machinestate.Stack_Omni[-1] + + def run_getglobal(self, opcodeint, immediates): + val = self.machinestate.Index_Space_Global[immediates[0]] + self.machinestate.Stack_Omni.append(val) + + def run_setglobal(self, opcodeint, immediates): + val = self.machinestate.Stack_Omni.pop() + self.machinestate.Index_Space_Global = val + + # currently only one linear memory is allowed so thats the default. + def run_load(self, opcodeint, immediates): + if opcodeint == 40: + bytes = self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates) + 4] + self.machinestate.Stack_Omni.append(np.int32(bytes)) + elif opcodeint == 41: + bytes = self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates) + 8] + self.machinestate.Stack_Omni.append(np.int64(bytes)) + elif opcodeint == 42: + bytes = self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates) + 4] + self.machinestate.Stack_Omni.append(np.float32(bytes)) + elif opcodeint == 43: + bytes = self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates) + 8] + self.machinestate.Stack_Omni.append(np.float64(bytes)) + elif opcodeint == 44: + temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1])]) + temp2 = (temp & 0x0000007f) | ((temp & 0x80) << 24) + self.machinestate.append(np.int32(tmep2)) + elif opcodeint == 45: + temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1])]) + temp2 = temp & 0x000000ff + self.machinestate.append(np.uint32(tmep2)) + elif opcodeint == 46: + temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 2)]) + temp2 = (temp & 0x00007fff) | ((temp & 0x8000) << 16) + self.machinestate.append(np.int32(tmep2)) + elif opcodeint == 47: + temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 2)]) + temp2 = temp & 0x0000ffff + self.machinestate.append(np.uint32(tmep2)) + elif opcodeint == 48: + temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1])]) + temp2 = (temp & 0x000000000000007f) | ((temp & 0x80) << 56) + self.machinestate.append(np.int64(tmep2)) + elif opcodeint == 49: + temp = np.uint8(self.machinestate.Linear_Memory[0][int(immediates[1])]) + self.machinestate.append(np.uint64(tmep)) + elif opcodeint == 50: + temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 2)]) + temp2 = (temp & 0x0000000000007fff) | ((temp & 0x8000) << 48) + self.machinestate.append(np.int64(tmep2)) + elif opcodeint == 51: + temp = np.uint8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 2)]) + self.machinestate.append(np.uint64(tmep)) + elif opcodeint == 52: + temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 4)]) + temp2 = (temp & 0x000000007fffffff) | ((temp & 0x80000000) << 32) + self.machinestate.append(np.int64(tmep2)) + elif opcodeint == 53: + temp = np.uint8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 4)]) + self.machinestate.append(np.uint64(tmep)) + else: + raise Exception(Colors.red + 'invalid load instruction.' + Colors.ENDC) + + # currently only one linear memory is allowed so thats the default. + def run_store(self, opcodeint, immediates): + if opcodeint == 54: + val = self.machinestate.Stack_Omni.pop() + self.machinestate.Linear_Memory[0][int(immediates[1]) + 0] = val & 0x000000ff + self.machinestate.Linear_Memory[0][int(immediates[1]) + 1] = val & 0x0000ff00 >> 8 + self.machinestate.Linear_Memory[0][int(immediates[1]) + 2] = val & 0x00ff0000 >> 16 + self.machinestate.Linear_Memory[0][int(immediates[1]) + 3] = val & 0xff000000 >> 24 + elif opcodeint == 55: + val = self.machinestate.Stack_Omni.pop() + self.machinestate.Linear_Memory[0][int(immediates[1]) + 0] = val & 0x00000000000000ff + self.machinestate.Linear_Memory[0][int(immediates[1]) + 1] = val & 0x000000000000ff00 >> 8 + self.machinestate.Linear_Memory[0][int(immediates[1]) + 2] = val & 0x0000000000ff0000 >> 16 + self.machinestate.Linear_Memory[0][int(immediates[1]) + 3] = val & 0x00000000ff000000 >> 24 + self.machinestate.Linear_Memory[0][int(immediates[1]) + 4] = val & 0x000000ff00000000 >> 32 + self.machinestate.Linear_Memory[0][int(immediates[1]) + 5] = val & 0x0000ff0000000000 >> 40 + self.machinestate.Linear_Memory[0][int(immediates[1]) + 6] = val & 0x00ff000000000000 >> 48 + self.machinestate.Linear_Memory[0][int(immediates[1]) + 7] = val & 0xff00000000000000 >> 56 + # @DEVI-FIXME-needs reinterpret cast + elif opcodeint == 56: + pass + # @DEVI-FIXME-needs reinterpret cast + elif opcodeint == 57: + pass + elif opcodeint == 58: + val = self.machinestate.Stack_Omni.pop() + self.machinestate.Linear_Memory[0][int(immediates[1])] = np.in8(val & 0x000000ff) + elif opcodeint == 59: + val = self.machinestate.Stack_Omni.pop() + self.machinestate.Linear_Memory[0][int(immediates[1]) + 0] = np.in8(val & 0x000000ff) + self.machinestate.Linear_Memory[0][int(immediates[1]) + 1] = np.in8(val & 0x0000ff00 >> 8) + elif opcodeint == 60: + val = self.machinestate.Stack_Omni.pop() + self.machinestate.Linear_Memory[0][int(immediates[1])] = np.in8(val & 0x00000000000000ff) + elif opcodeint == 61: + val = self.machinestate.Stack_Omni.pop() + self.machinestate.Linear_Memory[0][int(immediates[1]) + 0] = np.in8(val & 0x00000000000000ff) + self.machinestate.Linear_Memory[0][int(immediates[1]) + 1] = np.in8(val & 0x000000000000ff00 >> 8) + elif opcodeint == 62: + val = self.machinestate.Stack_Omni.pop() + self.machinestate.Linear_Memory[0][int(immediates[1]) + 0] = np.in8(val & 0x00000000000000ff) + self.machinestate.Linear_Memory[0][int(immediates[1]) + 1] = np.in8(val & 0x000000000000ff00 >> 8) + self.machinestate.Linear_Memory[0][int(immediates[1]) + 2] = np.in8(val & 0x0000000000ff0000 >> 16) + self.machinestate.Linear_Memory[0][int(immediates[1]) + 3] = np.in8(val & 0x00000000ff000000 >> 24) + else: + raise Exception(Colors.red + 'invalid store instruction' + Colors.ENDC) + + def run_current_memory(self, opcodeint, immediates): + pass + + def run_grow_memory(self, opcodeint, immediates): + pass + + def run_const(self, opcodeint, immediates): + if opcodeint == 65: + self.machinestate.Stack_Omni.append(immediates[0]) + elif opcodeint == 66: + self.machinestate.Stack_Omni.append(immediates[0]) + elif opcodeint == 67: + self.machinestate.Stack_Omni.append(immediates[0]) + elif opcodeint == 68: + self.machinestate.Stack_Omni.append(immediates[0]) + else: + raise Exception(Colors.red + 'invalid const instruction' + Colors.ENDC) + + def run_eqz(self, opcodeint, immediates): + if opcodeint == 69 or opcodeint == 80: + val = self.machinestate.Stack_Omni.pop() + if val == 0: + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid eqz instruction' + Colors.ENDC) + + def run_eq(self, opcodeint, immediates): + if opcodeint == 70 or opcodeint == 81 or opcodeint == 91 or opcodeint == 97: + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if val1 == val2: + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid eq instruction' + Colors.ENDC) + + def run_ne(self, opcodeint, immediates): + if opcodeint == 71 or opcodeint == 82 or opcodeint == 92 or opcodeint == 98: + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if val1 != val2: + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid ne instruction' + Colors.ENDC) + + def run_lt_s(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 72: + if np.int32(val1) < np.int32(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 83: + if np.int64(val1) < np.int64(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid lt_s instruction' + Colors.ENDC) + + def run_lt_u(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 73: + if np.uint32(val1) < np.uint32(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 84: + if np.uint64(val1) < np.uint64(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid lt_u instruction' + Colors.ENDC) + + def run_gt_s(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 74: + if np.int32(val1) > np.int32(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 85: + if np.int64(val1) > np.int64(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid gt_s instruction' + Colors.ENDC) + + def run_gt_u(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 75: + if np.uint32(val1) > np.uint32(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 86: + if np.uint64(val1) > np.uint64(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid gt_u instruction' + Colors.ENDC) + + def run_le_s(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 76: + if np.int32(val1) <= np.int32(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 87: + if np.int64(val1) <= np.int64(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid le_s instruction' + Colors.ENDC) + + def run_le_u(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 77: + if np.uint32(val1) <= np.uint32(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 88: + if np.uint64(val1) <= np.uint64(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid le_u instruction' + Colors.ENDC) + + def run_ge_s(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 78: + if np.int32(val1) >= np.int32(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 89: + if np.int64(val1) >= np.int64(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid ge_s instruction' + Colors.ENDC) + + def run_ge_u(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 79: + if np.uint32(val1) >= np.uint32(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 90: + if np.uint64(val1) >= np.uint64(val2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid ge_u instruction' + Colors.ENDC) + + def run_lt(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 93: + if np.float32(v1) < np.float32(v2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 99: + if np.float64(v1) < np.float64(v2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid lt instruction' + Colors.ENDC) + + def run_gt(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 94: + if np.float32(v1) > np.float32(v2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 100: + if np.float64(v1) > np.float64(v2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid gt instruction' + Colors.ENDC) + + def run_le(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 95: + if np.float32(v1) <= np.float32(v2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 101: + if np.float64(v1) <= np.float64(v2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid le instruction' + Colors.ENDC) + + def run_ge(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 96: + if np.float32(v1) >= np.float32(v2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + elif opcodeint == 102: + if np.float64(v1) >= np.float64(v2): + self.machinestate.Stack_Omni.append(1) + else: + self.machinestate.Stack_Omni.append(0) + else: + raise Exception(Colors.red + 'invalid ge instruction' + Colors.ENDC) + + def run_clz(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 103: + self.machinestate.Stack_Omni.append(clz(val, 'uint32')) + elif opcodeint == 121: + self.machinestate.Stack_Omni.append(clz(val, 'uint64')) + else: + raise Exception(Colors.red + 'invalid clz instruction' + Colors.ENDC) + + def run_ctz(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 104: + self.machinestate.Stack_Omni.append(ctz(val, 'uint32')) + elif opcodeint == 122: + self.machinestate.Stack_Omni.append(ctz(val, 'uint64')) + else: + raise Exception(Colors.red + 'invalid ctz instruction' + Colors.ENDC) + + def run_popcnt(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 105: + self.machinestate.Stack_Omni.append(pop_cnt(val, 'uint32')) + elif opcodeint == 123: + self.machinestate.Stack_Omni.append(pop_cnt(val, 'uint64')) + else: + raise Exception(Colors.red + 'invalid popcnt instruction' + Colors.ENDC) + + def run_add(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 106: + self.machinestate.Stack_Omni.append(np.uint32(val1 + val2)) + elif opcodeint == 124: + self.machinestate.Stack_Omni.append(np.uint64(val1 + val2)) + elif opcodeint == 146: + self.machinestate.Stack_Omni.append(np.float32(val1 + val2)) + elif opcodeint == 160: + self.machinestate.Stack_Omni.append(np.float64(val1 + val2)) + else: + raise Exception(Colors.red + 'invalid add instruction' + Colors.ENDC) + + def run_sub(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 107: + self.machinestate.Stack_Omni.append(np.uint32(val1 - val2)) + elif opcodeint == 125: + self.machinestate.Stack_Omni.append(np.uint64(val1 - val2)) + elif opcodeint == 147: + self.machinestate.Stack_Omni.append(np.float32(val1 - val2)) + elif opcodeint == 161: + self.machinestate.Stack_Omni.append(np.float64(val1 - val2)) + else: + raise Exception(Colors.red + 'invalid sub instruction' + Colors.ENDC) + + def run_mul(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 108: + self.machinestate.Stack_Omni.append(np.uint32(val1 * val2)) + elif opcodeint == 126: + self.machinestate.Stack_Omni.append(np.uint64(val1 * val2)) + elif opcodeint == 148: + self.machinestate.Stack_Omni.append(np.float32(val1 * val2)) + elif opcodeint == 162: + self.machinestate.Stack_Omni.append(np.float64(val1 * val2)) + else: + raise Exception(Colors.red + 'invalid mul instruction' + Colors.ENDC) + + def run_div_s(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 109: + self.machinestate.Stack_Omni.append(np.int32(np.int32(val1) / np.int32(val2))) + elif opcodeint == 127: + self.machinestate.Stack_Omni.append(np.int64(np.int64(val1) / np.int64(val2))) + else: + raise Exception(Colors.red + 'invalid div_s instruction' + Colors.ENDC) + + def run_div_u(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 110: + self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) / np.uint32(val2))) + elif opcodeint == 128: + self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) / np.uint64(val2))) + else: + raise Exception(Colors.red + 'invalid div_u instruction' + Colors.ENDC) + + def run_rem_s(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 111: + self.machinestate.Stack_Omni.append(np.int32(np.int32(val1) % np.int32(val2))) + elif opcodeint == 129: + self.machinestate.Stack_Omni.append(np.int64(np.int64(val1) % np.int64(val2))) + else: + raise Exception(Colors.red + 'invalid rem_s instruction' + Colors.ENDC) + + def run_rem_u(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 112: + self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) % np.uint32(val2))) + elif opcodeint == 130: + self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) % np.uint64(val2))) + else: + raise Exception(Colors.red + 'invalid rem_u instruction' + Colors.ENDC) + + def run_and(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 113: + self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) & np.uint32(val2))) + elif opcodeint == 131: + self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) & np.uint64(val2))) + else: + raise Exception(Colors.red + 'invalid and instruction' + Colors.ENDC) + + def run_or(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 114: + self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) | np.uint32(val2))) + elif opcodeint == 132: + self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) | np.uint64(val2))) + else: + raise Exception(Colors.red + 'invalid or instruction' + Colors.ENDC) + + def run_xor(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 115: + self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) ^ np.uint32(val2))) + elif opcodeint == 133: + self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) ^ np.uint64(val2))) + else: + raise Exception(Colors.red + 'invalid xor instruction' + Colors.ENDC) + + def run_shl(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 116: + self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) << (np.uint32(val2)))) + elif opcodeint == 134: + self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) << (np.uint64(val2)))) + else: + raise Exception(Colors.red + 'invalid shl instruction' + Colors.ENDC) + + def run_shr_s(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 117: + self.machinestate.Stack_Omni.append(np.int32(np.int32(val1) >> (np.int32(val2)))) + elif opcodeint == 135: + self.machinestate.Stack_Omni.append(np.int64(np.int64(val1) >> (np.int64(val2)))) + else: + raise Exception(Colors.red + 'invalid shr_s instruction' + Colors.ENDC) + + def run_shr_u(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 118: + self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) >> (np.uint32(val2)))) + elif opcodeint == 136: + self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) >> (np.uint64(val2)))) + else: + raise Exception(Colors.red + 'invalid shr_u instruction' + Colors.ENDC) + + def run_rotl(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 119: + self.machinestate.Stack_Omni.append(rol(val1, 32, val2)) + elif opcodeint == 137: + self.machinestate.Stack_Omni.append(rol(val1, 64, val2)) + else: + raise Exception(Colors.red + 'invalid rotl instruction' + Colors.ENDC) + + def run_rotr(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 120: + self.machinestate.Stack_Omni.append(ror(val1, 32, val2)) + elif opcodeint == 138: + self.machinestate.Stack_Omni.append(ror(val1, 32, val2)) + else: + raise Exception(Colors.red + 'invalid rotl instruction' + Colors.ENDC) + + def run_abs(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 139 or opcodeint == 153: + self.machinestate.Stack_Omni.append(abs(val1)) + else: + raise Exception(Colors.red + 'invalid abs instruction' + Colors.ENDC) + + def run_neg(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 140 or opcodeint == 154: + self.machinestate.Stack_Omni.append(-val1) + else: + raise Exception(Colors.red + 'invalid neg instruction' + Colors.ENDC) + + def run_ceil(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 141 or opcodeint == 155: + self.machinestate.Stack_Omni.append(math.ceil(val1)) + else: + raise Exception(Colors.red + 'invalid ceil instruction' + Colors.ENDC) + + def run_floor(self, opcodeint, immediates): + if opcodeint == 142 or opcodeint == 156: + self.machinestate.Stack_Omni.append(math.floor(val1)) + else: + raise Exception(Colors.red + 'invalid floor instruction' + Colors.ENDC) + + def run_trunc(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 143 or opcodeint == 157: + self.machinestate.Stack_Omni.append(math.trunc(val1)) + else: + raise Exception(Colors.red + 'invalid trunc instruction' + Colors.ENDC) + + def run_nearest(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 144 or opcodeint == 158: + self.machinestate.Stack_Omni.append(round(val1)) + else: + raise Exception(Colors.red + 'invalid nearest instruction' + Colors.ENDC) + + def run_sqrt(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 145 or opcodeint == 159: + self.machinestate.Stack_Omni.append(math.sqrt(val1)) + else: + raise Exception(Colors.red + 'invalid sqrt instruction' + Colors.ENDC) + + def run_div(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 149: + self.machinestate.Stack_Omni.append(v1 / v2) + else: + raise Exception(Colors.red + 'invalid float div instruction' + Colors.ENDC) + + def run_min(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 150 or opcodeint == 164: + self.machinestate.Stack_Omni.append(min(val1, val2)) + else: + raise Exception(Colors.red + 'invalid min instruction' + Colors.ENDC) + + def run_max(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 151 or opcodeint == 165: + self.machinestate.Stack_Omni.append(max(val1, val2)) + else: + raise Exception(Colors.red + 'invalid max instruction' + Colors.ENDC) + + def run_copysign(self, opcodeint, immediates): + val2 = self.machinestate.Stack_Omni.pop() + val1 = self.machinestate.Stack_Omni.pop() + if opcodeint == 152 or opcodeint == 166: + self.machinestate.Stack_Omni.append(math.copysign(val1, val2)) + else: + raise Exception(Colors.red + 'invalid max instruction' + Colors.ENDC) + + def run_i32wrapi64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.int32(np.float64(val1))) + + def run_i32trunc_sf32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.int32(np.float32(val1))) + + def run_i32trunc_uf32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.uint32(np.float32(val1))) + + def run_i32trunc_sf64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.int32(np.float64(val1))) + + def run_i32trunc_uf64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.int32(np.float64(val1))) + + def run_i64extend_si32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float64(np.int32(val1))) + + def run_i64extend_ui32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float64(np.uint32(val1))) + + def run_i64trunc_sf32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.int64(np.float32(val1))) + + def run_i64trunc_uf32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.uint64(np.float32(val1))) + + def run_i64trunc_sf64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.int64(np.float64(val1))) + + def run_i64trunc_uf64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.uint64(np.float64(val1))) + + def run_f32convert_si32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float32(np.uint32(val1))) + + def run_f32convert_ui32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float32(np.int32(val1))) + + def run_f32convert_si64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float32(np.int64(val1))) + + def run_f32convert_ui64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float32(np.uint64(val1))) + + def run_f32demotef64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float32(np.float64(val1))) + + def run_f64convert_si32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float64(np.int32(val1))) + + def run_f64convert_ui32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float64(np.uint32(val1))) + + def run_f64convert_si64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float64(np.int64(val1))) + + def run_f64convert_ui64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float64(np.uint64(val1))) + + def run_f64promotef32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + self.machinestate.Stack_Omni.append(np.float64(np.float32(val1))) + + def run_i32reinterpretf32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + sel.machinestate.Stack_Omni.append(reinterpretf32toi32(val1)) + + def run_i64reinterpretf64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + sel.machinestate.Stack_Omni.append(reinterpretf64toi64(val1)) + + def run_f32reinterpreti32(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + sel.machinestate.Stack_Omni.append(reinterpreti32tof32(val1)) + + def run_f64reinterpreti64(self, opcodeint, immediates): + val1 = self.machinestate.Stack_Omni.pop() + sel.machinestate.Stack_Omni.append(reinterpreti64tof64(val1)) diff --git a/init.py b/init.py new file mode 100644 index 0000000..f3ac986 --- /dev/null +++ b/init.py @@ -0,0 +1,415 @@ +from utils import Colors, init_interpret, ParseFlags +from opcodes import WASM_OP_Code +from section_structs import Code_Section, Func_Body, WASM_Ins, Resizable_Limits, Memory_Section +from execute import * +import datetime as dti +import os +import sys +import signal + + +# McCabe cyclomatic complexity metric +class Metric(): + def __init__(self, code_section): + self.code_section = code_section + self.metric = [] + self.soc = [] + + def mccabe(self): + soc = 0 + Edges = 1 + Nodes = 1 + for funcs in self.code_section.func_bodies: + for ins in funcs.code: + soc += 1 + #print(repr(ins.opcodeint)) + if ins.opcodeint == 4 or ins.opcodeint == 5 or ins.opcodeint == 12 \ + or ins.opcodeint == 13 or ins.opcodeint == 14: + Nodes += 2 + Edges += 4 + elif ins.opcode == 3: + Nodes += 2 + Edges += 3 + else: + pass + + self.metric.append(Edges - Nodes + 1) + self.soc.append(soc) + soc = 0 + Edges = 1 + Nodes = 1 + + def getMcCabe(self): + return self.metric + + def getSOC(self): + return self.soc + + +# handles the debug option --memdump. dumps the contents of linear memories. +def DumpLinearMems(linear_memories, threshold): + count = int() + strrep = [] + linmem_cnt = int() + for lin_mem in linear_memories: + print('-----------------------------------------') + print(Colors.blue + Colors.BOLD + 'Linear Memory '+ repr(linmem_cnt)+ ' :' + Colors.ENDC) + for byte in lin_mem: + if count >= threshold: + break + if count%16 == 0: + for ch in strrep: + # @DEVI-line feed messes the pretty format up + if ord(ch) != 10: + print(Colors.green + ' ' + ch + Colors.ENDC, end = '') + else: + pass + print() + strrep = [] + print(Colors.cyan + hex(count), ':\t' + Colors.ENDC, end='') + strrep.append(str(chr(byte))) + print(Colors.blue + format(byte, '02x') + ' ' + Colors.ENDC, end='') + else: + strrep += str(chr(byte)) + print(Colors.blue + format(byte, '02x') + ' ' + Colors.ENDC, end='') + count += 1 + count = 0 + print() + + +# handles the debug options --idxspc. dumps the index spaces. +def DumpIndexSpaces(machinestate): + print('-----------------------------------------') + print(Colors.green + 'Function Index Space: ' + Colors.ENDC) + for iter in machinestate.Index_Space_Function: + print(Colors.blue + repr(iter) + Colors.ENDC) + + print('-----------------------------------------') + print(Colors.green + 'Globa Index Space: ' + Colors.ENDC) + for iter in machinestate.Index_Space_Global: + print(Colors.blue + repr(iter) + Colors.ENDC) + + print('-----------------------------------------') + print(Colors.green + 'Linear Memory Index Space: ' + Colors.ENDC) + for iter in machinestate.Index_Space_Linear: + print(Colors.blue + repr(iter) + Colors.ENDC) + + print('-----------------------------------------') + print(Colors.green + 'Table Index Space: ' + Colors.ENDC) + for iter in machinestate.Index_Space_Table: + print(Colors.blue + repr(iter) + Colors.ENDC) + print('-----------------------------------------') + + +# WIP-the Truebit Machine class +class TBMachine(): + def __init__(self): + # bytearray of size PAGE_SIZE + self.Linear_Memory = [] + self.Stack_Label = list() + self.Stack_Label_Height = int() + self.Stack_Control_Flow = list() + self.Stack_Call = list() + self.Stack_Value = list() + self.Stack_Omni = list() + self.Vector_Globals = list() + self.Index_Space_Function = list() + self.Index_Space_Global = list() + self.Index_Space_Linear = list() + self.Index_Space_Table = list() + self.Index_Space_Locals = list() + self.Index_Space_Label = list() + + +# handles the initialization of the WASM machine +class TBInit(): + def __init__(self, module, machinestate): + self.module = module + self.machinestate = machinestate + + # a convenience function that runs the methods of the class. all methods + # can be called separately manually as well. + def run(self): + self.InitFuncIndexSpace() + self.InitGlobalIndexSpace() + self.InitLinearMemoryIndexSpace() + self.InitTableIndexSpace() + self.InitializeLinearMemory() + + def InitFuncIndexSpace(self): + if self.module.import_section is not None: + for iter in self.module.import_section.import_entry: + if iter.kind == 0: + name = str() + for i in iter.field_str: + name += str(chr(i)) + self.machinestate.Index_Space_Function.append(name) + + if self.module.function_section is not None: + for iter in self.module.function_section.type_section_index: + self.machinestate.Index_Space_Function.append(iter) + + def InitGlobalIndexSpace(self): + if self.module.import_section is not None: + for iter in self.module.import_section.import_entry: + if iter.kind == 3: + name = str() + for i in iter.field_str: + name += str(chr(i)) + self.machinestate.Index_Space_Global.append(name) + + if self.module.global_section is not None: + for iter in self.module.global_section.global_variables: + self.machinestate.Index_Space_Global.append(iter.init_expr) + + def InitLinearMemoryIndexSpace(self): + if self.module.import_section is not None: + for iter in self.module.import_section.import_entry: + if iter.kind == 2: + name = str() + for i in iter.field_str: + name += str(chr(i)) + self.machinestate.Index_Space_Linear.append(name) + + if self.module.memory_section is not None: + for iter in self.module.memory_section.memory_types: + self.machinestate.Index_Space_Linear.append(iter.initial) + + def InitTableIndexSpace(self): + if self.module.import_section is not None: + for iter in self.module.import_section.import_entry: + if iter.kind == 1: + name = str() + for i in iter.field_str: + name += str(chr(i)) + self.machinestate.Index_Space_Table.append(name) + + if self.module.table_section is not None: + for iter in self.module.table_section.table_types: + self.machinestate.Index_Space_Table.append(iter.element_type) + + def InitializeLinearMemory(self): + # @DEVI-we could try to pack the data in the linear memory ourselve to + # decrease the machinestate size + if self.module.memory_section is None: + rsz_limits = Resizable_Limits() + self.module.memory_section = Memory_Section() + self.module.memory_section.memory_types = [rsz_limits] + self.module.memory_section.count = 1 + for iter in self.module.memory_section.memory_types: + self.machinestate.Linear_Memory.append(bytearray( + WASM_OP_Code.PAGE_SIZE)) + if self.module.data_section is not None: + for iter in self.module.data_section.data_segments: + count = int() + for byte in iter.data: + self.machinestate.Linear_Memory[iter.index][init_interpret(iter.offset) + count] = byte + count += 1 + + # returns the machinestate + def getInits(self): + return(self.machinestate) + + +# WIP-holds the run-rime data structures for a wasm machine +class RTE(): + def __init__(self): + Stack_Control_Flow = list() + Stack_Value = list() + Vector_Locals = list() + Current_Position = int() + Local_Stacks = list() + + def genFuncLocalStack(func_body): + pass + + +# palceholder for the class that holds the validation functions +class ModuleValidation(): + def __init__(self, module): + self.module = module + + def TypeSection(self): + pass + + def ImportSection(self): + pass + + def FunctionSection(self): + pass + + def TableSection(self): + pass + + def MemorySection(self): + pass + + def GlobalSection(self): + pass + + def ExportSection(self): + pass + + def StartSection(self): + pass + + def ElementSection(self): + pass + + def CodeSection(self): + pass + + def DataSection(self): + pass + + def TBCustom(self): + pass + + def ValidateAll(self): + self.TypeSection() + self.ImportSection() + self.FunctionSection() + self.TableSection() + self.MemorySection() + self.GlobalSection() + self.ExportSection() + self.StartSection() + self.ElementSection() + self.CodeSection() + self.DataSection() + self.TBCustom() + + return(True) + + +# a convinience class that handles the initialization of the wasm machine and +# interpretation of the code. +class VM(): + def __init__(self, modules): + self.modules = modules + self.machinestate = TBMachine() + # @DEVI-FIXME- the first implementation is single-module only + self.init = TBInit(self.modules[0], self.machinestate) + self.init.run() + self.machinestate = self.init.getInits() + self.start_function = Func_Body() + self.ins_cache = WASM_Ins() + self.executewasm = Execute(self.machinestate) + self.totGas = int() + self.metric = Metric(modules[0].code_section) + self.parseflags = None + + def setFlags(self, parseflags): + self.parseflags = parseflags + + def getState(self): + return(self.machinestate) + + def initLocalIndexSpace(self, local_count): + for i in range(0, local_count): + self.machinestate.Index_Space_Locals.append(0) + + def getStartFunctionIndex(self): + if self.modules[0].start_section is None: + if self.parseflags.entry is None: + raise Exception(Colors.red + "module does not have a start section. no function index was provided with the --entry option.quitting..." + Colors.ENDC) + else: + start_index = int(self.parseflags.entry) + else: + print(Colors.green + "found start section: " + Colors.ENDC, end = '') + start_index = self.modules[0].start_section.function_section_index + + print(Colors.blue + Colors.BOLD + "running function at index " + repr(start_index) + Colors.ENDC) + if (start_index > len(self.modules[0].code_section.func_bodies) - 1): + raise Exception(Colors.red + "invalid function index: the function index does not exist." + Colors.ENDC) + return(start_index) + + def getStartFunctionBody(self): + start_index = self.getStartFunctionIndex() + if isinstance(start_index, int): + self.start_function = self.modules[0].code_section.func_bodies[start_index] + elif isinstance(start_index, str): + # we have to import the function from another module/library. we + # assume sys calls are not present.:w + pass + else: + raise Exception(Colors.red + "invalid entry for start function index" + Colors.ENDC) + + def execute(self): + print(Colors.blue + Colors.BOLD + 'running module with code: ' + Colors.ENDC) + for ins in self.start_function.code: + print(Colors.purple + repr(ins.opcode) + ' ' + repr(ins.operands) + Colors.ENDC) + for ins in self.start_function.code: + self.executewasm.getInstruction(ins.opcodeint, ins.operands) + self.executewasm.callExecuteMethod() + self.getState() + + # pre-execution hook + def startHook(self): + if self.parseflags.metric: + for mem in self.modules[0].memory_section.memory_types: + self.executewasm.chargeGasMem(mem.initial) + + self.metric.mccabe() + print(Colors.red + "mccabe: " + repr(self.metric.getMcCabe()) + Colors.ENDC) + print(Colors.red + "soc: " + repr(self.metric.getSOC()) + Colors.ENDC) + + # post-execution hook + def endHook(self): + if self.parseflags.gas: + self.totGas = self.executewasm.getOPGas() + print(Colors.red + "total gas cost: " + repr(self.totGas) + Colors.ENDC) + if self.machinestate.Stack_Omni: + print(Colors.green + "stack top: " + repr(self.machinestate.Stack_Omni.pop()) + Colors.ENDC) + + # a convinience method + def run(self): + self.startHook() + self.getStartFunctionBody() + self.initLocalIndexSpace(self.start_function.local_count) + self.execute() + self.endHook() + + +# a wrapper class for VM. it timeouts instructions that take too long to +# execute. +class Judicator(): + def __int__(self, op_time_table, module): + self.op_time_table = op_time_table + self.vm = VM(modules) + self.vm.getStartFunctionBody() + + def overseer(): + # @DEVI- forking introduces a new source of non-determinism + pid = os.fork() + # child process + if pid == 0: + sys.stdout = open('./jstdout', 'w') + sys.stderr = open('./jstderr', 'w') + self.vm.execute() + sys.exit() + # parent process + if pid > 0: + cpid, status = os.waitpid(pid, 0) + if status == 0: + print('overseer child exited successfully.') + else: + print('overseer child exited with non-zero.') + # pid < 0 + else: + raise Exception(Colors.red + 'could not fork judicator overseer.' + Colors.ENDC) + + def setup(self): + signal.signal(signal.SIGALRM, self.to_sighandler) + + def set_alarm(t): + signal.alaram(t) + + def to_sighandler(signum, frame): + print(Colors.red + "execution time out..." + Colors.ENDC) + raise Exception(Colors.red + "execution time out" + Colors.ENDC) + + def run(self): + self.setup() + self.set_alaram(10) + self.overseer() diff --git a/linker.py b/linker.py new file mode 100644 index 0000000..7cf804b --- /dev/null +++ b/linker.py @@ -0,0 +1,2 @@ +import section_structs +import utils diff --git a/opcodes.py b/opcodes.py new file mode 100644 index 0000000..f7c9a1b --- /dev/null +++ b/opcodes.py @@ -0,0 +1,332 @@ +from enum import Enum + +SectionID = {0:"custom", 1:"type", 2:"import", 3:"function", 4:"table", 5:"memory", 6:"global", 7:"export", 8:"start", 9:"element", 10:"code", 11:"data", 63:"unknown"} + +class RelocType(Enum): + R_WEBASSEMBLY_FUNCTION_INDEX_LEB = 0 + R_WEBASSEMBLY_TABLE_INDEX_SLEB = 1 + R_WEBASSEMBLY_TABLE_INDEX_I32 = 2 + R_WEBASSEMBLY_MEMORY_ADDR_LEB = 3 + R_WEBASSEMBLY_MEMORY_ADDR_SLEB = 4 + R_WEBASSEMBLY_MEMORY_ADDR_I32 = 5 + R_WEBASSEMBLY_TYPE_INDEX_LEB = 6 + R_WEBASSEMBLY_GLOBAL_INDEX_LEB = 7 + R_WEBASSEMPLY_FUNCTION_OFFSET_I32 = 8 + R_WEBASSEMBLY_SECTION_OFFSET_I32 = 9 + +class LinkingSubsection(Enum): + WASM_SEGMENT_INFO = 5 + WASM_INIT_FUNCS = 6 + WASM_COMDAT_INFO = 7 + WASM_SYMBOL_TABLE = 8 + +class TypeType(Enum): + none = 1 + lebu = 2 + lebs = 3 + flot = 4 + dobl = 5 + +class Syminfo_Kind(): + SYMTAB_FUNCTION = 0 + SYMTAB_DATA = 1 + SYMTAB_GLOBAL = 2 + SYMTAB_SECTION = 3 + +TypeKS = [['uint8', 8, TypeType.none], ['uint16', 16, TypeType.none], + ['uint32', 32, TypeType.none], ['uint64', 64, TypeType.none], + ['varuint1', 1, TypeType.lebu], ['varuint7', 7, TypeType.lebu], + ['varuint32', 32, TypeType.lebu], ['varuint64', 64, TypeType.lebu], + ['varint1', 1, TypeType.lebs], ['varint7', 7, TypeType.lebs], + ['varint32', 32, TypeType.lebs], ['varint64', 64, TypeType.lebs]] + +TypeDic = {'uint8': 1, 'uint16': 2, 'uint32': 4, 'uint64': 8, + 'varuint1': 1, 'varuint7': 1, 'varuint32': 4, 'varuint64': 8, + 'varint1': 1, 'varint7': 1, 'varint32': 4, 'varint64': 8} + +# holds the version 1.0 wasm opcodes and immediates +class WASM_OP_Code: + version_number = 0x01 + magic_number = 0x6d736100 + PAGE_SIZE = 65536 + uint8 = 1 + uint16 = 2 + uint32 = 4 + uint64 = 8 + varuint1 = 1 + varuint7 = 1 + varuint32 = 4 + varuint64 = 8 + varint1 = 1 + varint7 = 1 + varint32 = 4 + varint64 = 8 + floatt = 4 + doublet = 8 + + all_ops = [('i32', '7f', False), ('i64', '7e', False), ('f32', '7d', False), + ('f64', '7c', False), ('anyfunc', '7b', False), + ('func', '60', False), ('empty_block_type', '40', False), + ('unreachable', '00', False), ('nop', '01', False), + ('block', '02', True, ('varuint7')), + ('loop', '03', True, ('varuint7')), + ('if', '04', True, ('varuint7')), ('else', '05', False), + ('end', '0b', False), ('br', '0c', True, ('varuint32')), + ('br_if', '0d', True, ('varuint32')), + ('br_table', '0e', True, ('varuint32', 'varuint32', 'varuint32')), + ('return', '0f', False), ('call', '10', True, ('varuint32')), + ('call_indirect', '11', True, ('varuint32', 'varuint1')), + ('drop', '1a', False), ('select', '1b', False), + ('get_local', '20', True, ('varuint32')), + ('set_local', '21', True, ('varuint32')), + ('tee_local', '22', True, ('varuint32')), + ('get_global', '23', True, ('varuint32')), + ('set_global', '24', True, ('varuint32')), + ('i32.load', '28', True, ('varuint32', 'varuint32')), + ('i64.load', '29', True, ('varuint32', 'varuint32')), + ('f32.load', '2a', True, ('varuint32', 'varuint32')), + ('f64.load', '2b', True, ('varuint32', 'varuint32')), + ('i32.load8_s', '2c', True, ('varuint32', 'varuint32')), + ('i32.load8_u', '2d', True, ('varuint32', 'varuint32')), + ('i32.load16_s', '2e', True, ('varuint32', 'varuint32')), + ('i32.load16_u', '2f', True, ('varuint32', 'varuint32')), + ('i64.load8_s', '30', True, ('varuint32', 'varuint32')), + ('i64.load8_u', '31', True, ('varuint32', 'varuint32')), + ('i64.load16_s', '32', True, ('varuint32', 'varuint32')), + ('i64.load16_u', '33', True, ('varuint32', 'varuint32')), + ('i64.load32_s', '34', True, ('varuint32', 'varuint32')), + ('i64.load32_u', '35', True, ('varuint32', 'varuint32')), + ('i32.store', '36', True, ('varuint32', 'varuint32')), + ('i64.store', '37', True, ('varuint32', 'varuint32')), + ('f32.store', '38', True, ('varuint32', 'varuint32')), + ('f64.store', '39', True, ('varuint32', 'varuint32')), + ('i32.store8', '3a', True, ('varuint32', 'varuint32')), + ('i32.store16', '3b', True, ('varuint32', 'varuint32')), + ('i64.store8', '3c', True, ('varuint32', 'varuint32')), + ('i64.store16', '3d', True, ('varuint32', 'varuint32')), + ('i64.store32', '3e', True, ('varuint32', 'varuint32')), + ('current_memory', '3f', True, ('varuint1')), + ('grow_memory', '40', True, ('varuint1')), + ('i32.const', '41', True, ('varint32')), + ('i64.const', '42', True, ('varint64')), + ('f32.const', '43', True, ('uint32')), + ('f64.const', '44', True, ('uint64')), + ('i32.eqz', '45', False), ('i32.eq', '46', False), + ('i32.ne', '47', False), ('i32.lt_s', '48', False), + ('i32.lt_u', '49', False), ('i32.gt_s', '4a', False), + ('i32.gt_u', '4b', False), ('i32.le_s', '4c', False), + ('i32.le_u', '4d', False), ('i32.ge_s', '4e', False), + ('i32.ge_u', '4f', False), ('i64.eqz', '50', False), + ('i64.eq', '51', False), ('i64.ne', '52', False), + ('i64.lt_s', '53', False), ('i64.lt_u', '54', False), + ('i64.gt_s', '55', False), ('i64.gt_u', '56', False), + ('i64.le_s', '57', False), ('i64.le_u', '58', False), + ('i64.ge_s', '59', False), ('i64.ge_u', '5a', False), + ('f32.eq', '5b', False), ('f32.ne', '5c', False), + ('f32.lt', '5d', False), ('f32.gt', '5e', False), + ('f32.le', '5f', False), ('f32.ge', '60', False), + ('f64.eq', '61', False), ('f64.ne', '62', False), + ('f64.lt', '63', False), ('f64.gt', '64', False), + ('f64.le', '65', False), ('f64.ge', '66', False), + ('i32.clz', '67', False), ('i32.ctz', '68', False), + ('i32.popcnt', '69', False), ('i32.add', '6a', False), + ('i32.sub', '6b', False), ('i32.mul', '6c', False), + ('i32.div_s', '6d', False), ('i32.div_u', '6e', False), + ('i32.rem_s', '6f', False), ('i32.rem_u', '70', False), + ('i32.and', '71', False), ('i32.or', '72', False), + ('i32.xor', '73', False), ('i32.shl', '74', False), + ('i32.shr_s', '75', False), ('i32.shr_u', '76', False), + ('i32.rotl', '77', False), ('i32.rotr', '78', False), + ('i64.clz', '79', False), ('i64.ctz', '7a', False), + ('i64.popcnt', '7b', False), ('i64.add', '7c', False), + ('i64.sub', '7d', False), ('i64.mul', '7e', False), + ('i64.div_s', '7f', False), ('i64.div_u', '80', False), + ('i64.rem_s', '81', False), ('i64.rem_u', '82', False), + ('i64.and', '83', False), ('i64.or', '84', False), + ('i64.xor', '85', False), ('i64.shl', '86', False), + ('i64.shr_s', '87', False), ('i64.shr_u', '88', False), + ('i64.rotl', '89', False), ('i63.rotr', '8a', False), + ('f32.abs', '8b', False), ('f32.neg', '8c', False), + ('f32.ceil', '8d', False), ('f32.floor', '8e', False), + ('f32.trunc', '8f', False), ('f32.nearest', '90', False), + ('f32.sqrt', '91', False), ('f32.add', '92', False), + ('f32.sub', '93', False), ('f32.mul', '94', False), + ('f32.div', '95', False), ('f32.min', '96', False), + ('f32.max', '97', False), ('f32.copysign', '98', False), + ('f64.abs', '99', False), ('f64.neg', '9a', False), + ('f64.ceil', '9b', False), ('f64.floor', '9c', False), + ('f64.trunc', '9d', False), ('f64.nearest', '9e', False), + ('f64.sqrt', '9f', False), ('f64.add', 'a0', False), + ('f64.sub', 'a1', False), ('f64.mul', 'a2', False), + ('f64.div', 'a3', False), ('f64.min', 'a4', False), + ('f64.max', 'a5', False), ('f64.copysign', 'a6', False), + ('i32.wrap/i64', 'a7', False), ('i32.trunc_s/f32', 'a8', False), + ('i32.trunc_u/f32', 'a9', False), + ('i32.trunc_s/f64', 'aa', False), + ('i32.trunc_u/f64', 'ab', False), + ('i64.extend_s/i32', 'ac', False), + ('i64.extend_u/i32', 'ad', False), + ('i64.trunc_s/f32', 'ae', False), + ('i64.trunc_u/f32', 'af', False), + ('i64.trunc_s/f64', 'b0', False), + ('i64.trunc_u/f64', 'b1', False), + ('f32.convert_s/i32', 'b2', False), + ('f32.convert_u/i32', 'b3', False), + ('f32.convert_s/i64', 'b4', False), + ('f32.convert_u/i64', 'b5', False), + ('f32.demote/f64', 'b6', False), + ('f64.convert_s/i32', 'b7', False), + ('f64.convert_u/i32', 'b8', False), + ('f64.convert_s/i64', 'b9', False), + ('f64.convert_u/i64', 'ba', False), + ('f64.promote/f32', 'bb', False), + ('i32.reinterpret/f32', 'bc', False), + ('i64.reinterpret/f64', 'bd', False), + ('f32.reinterpret/i32', 'be', False), + ('f64.reinterpret/i64', 'bf', False)] + + type_ops = [('i32', '7f'), ('i64', '7e'), ('f32', '7d'), + ('f64', '7c'), ('anyfunc', '7b'), ('func', '60'), + ('empty_block_type', '40')] + type_ops_dict = dict(type_ops) + type_ops_dict_rev = {v: k for k, v in type_ops_dict.items()} + + control_flow_ops = [('unreachable', '00'), ('nop', '01'), + ('block', '02'), ('loop', '03'), + ('if', '04'), ('else', '05'), + ('end', '0b'), ('br', '0c'), + ('br_if', '0d'), ('br_table', '0e'), + ('return', '0f')] + control_flow_ops_dict = dict(control_flow_ops) + control_flow_ops_dict_rev = {v: k for k, v in control_flow_ops_dict.items()} + + call_ops = [('call', '10'), ('call_indirect', '11')] + call_ops_dict = dict(call_ops) + call_ops_dict_rev = {v: k for k, v in call_ops_dict.items()} + + param_ops = [('drop', '1a'), ('select', '1b')] + param_ops_dict = dict(param_ops) + param_ops_dict_rev = {v: k for k, v in param_ops_dict.items()} + + var_access = [('get_local', '20'), ('set_local', '21'), + ('tee_local', '22'), ('get_global', '23'), + ('set_global', '24')] + var_access_dict = dict(var_access) + var_access_dict_rev = {v: k for k, v in var_access_dict.items()} + + mem_ops = [('i32.load', '28'), ('i64.load', '29'), + ('f32.load', '2a'), ('f64.load', '2b'), + ('i32.load8_s', '2c'), ('i32.load8_u', '2d'), + ('i32.load16_s', '2e'), ('i32.load16_u', '2f'), + ('i64.load8_s', '30'), ('i64.load8_u', '31'), + ('i64.load16_s', '32'), ('i64.load16_u', '33'), + ('i64.load32_s', '34'), ('i64.load32_u', '35'), + ('i32.store', '36'), ('i64.store', '37'), + ('f32.store', '38'), ('f64.store', '39'), + ('i32.store8', '3a'), ('i32.store16', '3b'), + ('i64.store8', '3c'), ('i64.store16', '3d'), + ('i64.store32', '3e'), ('current_memory', '3f'), + ('grow_memory', '40')] + mem_ops_dict = dict(mem_ops) + mem_ops_dict_rev = {v: k for k, v in mem_ops_dict.items()} + + consts = [('i32.const', '41'), ('i64.const', '42'), + ('f32.const', '43'), ('f64', '44')] + consts_dict = dict(consts) + consts_dict_rev = {v: k for k, v in consts_dict.items()} + + comp_ops = [('i32.eqz', '45'), ('i32.eq', '46'), ('i32.ne', '47'), + ('i32.lt_s', '48'), ('i32.lt_u', '49'), + ('i32.gt_s', '4a'), ('i32.gt_u', '4b'), + ('i32.le_s', '4c'), ('i32.le_u', '4d'), + ('i32.ge_s', '4e'), ('i32.ge_u', '4f'), + ('i64.eqz', '50'), ('i64.eq', '51'), + ('i64.ne', '52'), ('i64.lt_s', '53'), + ('i64.lt_u', '54'), ('i64.gt_s', '55'), + ('i64.gt_u', '56'), ('i64.le_s', '57'), + ('i64.le_u', '58'), ('i64.ge_s', '59'), + ('i64.ge_u', '5a'), ('f32.eq', '5b'), + ('f32.ne', '5c'), ('f32.lt', '5d'), + ('f32.gt', '5e'), ('f32.le', '5f'), + ('f32.ge', '60'), ('f64.eq', '61'), + ('f64.ne', '62'), ('f64.lt', '63'), + ('f64.gt', '64'), ('f64.le', '65'), + ('f64.ge', '66')] + comp_ops_dict = dict(comp_ops) + comp_ops_dict_rev = {v: k for k, v in comp_ops_dict.items()} + + num_ops = [('i32.clz', '67'), ('i32.ctz', '68'), + ('i32.popcnt', '69'), ('i32.add', '6a'), + ('i32.sub', '6b'), ('i32.mul', '6c'), + ('i32.div_s', '6d'), ('i32.div_u', '6e'), + ('i32.rem_s', '6e'), ('i32.rem_u', '70'), + ('i32.and', '71'), ('i32.or', '72'), + ('i32.xor', '73'), ('i32.shl', '74'), + ('i32.shr_s', '75'), ('i32.shr_u', '76'), + ('i32.rotl', '77'), ('i32.rotr', '78'), + ('i64.clz', '79'), ('i64.ctz', '7a'), + ('i64.popcnt', '7b'), ('i64.add', '7c'), + ('i64.sub', '7d'), ('i64.mul', '7e'), + ('i64.div_s', '7f'), ('i64.div_u', '80'), + ('i64.rem_s', '81'), ('i64.rem_u', '82'), + ('i64.and', '83'), ('i64.or', '84'), + ('i64.xor', '85'), ('i64.shl', '86'), + ('i64.shr_s', '87'), ('i64.shr_u', '88'), + ('i64.rotl', '89'), ('i63.rotr', '8a'), + ('f32.abs', '8b'), ('f32.neg', '8c'), + ('f32.ceil', '8d'), ('f32.floor', '8e'), + ('f32.trunc', '8f'), ('f32.nearest', '90'), + ('f32.sqrt', '91'), ('f32.add', '92'), + ('f32.sub', '93'), ('f32.mul', '94'), + ('f32.div', '95'), ('f32.min', '96'), + ('f32.max', '97'), ('f32.copysign', '98'), + ('f64.abs', '99'), ('f64.neg', '9a'), + ('f64.ceil', '9b'), ('f64.floor', '9c'), + ('f64.trunc', '9d'), ('f64.nearest', '9e'), + ('f64.sqrt', '9f'), ('f64.add', 'a0'), + ('f64.sub', 'a1'), ('f64.mul', 'a2'), + ('f64.div', 'a3'), ('f64.min', 'a4'), + ('f64.max', 'a5'), ('f64.copysign', 'a6')] + num_ops_dict = dict(num_ops) + num_ops_dict_rev = {v: k for k, v in num_ops_dict.items()} + + conversion = [('i32.wrap/i64', 'a7'), + ('i32.trunc_s/f32', 'a8'), + ('i32.trunc_u/f32', 'a9'), + ('i32.trunc_s/f64', 'aa'), + ('i32.trunc_u/f64', 'ab'), + ('i64.extend_s/i32', 'ac'), + ('i64.extend_u/i32', 'ad'), + ('i64.trunc_s/f32', 'ae'), + ('i64.trunc_u/f32', 'af'), + ('i64.trunc_s/f64', 'b0'), + ('i64.trunc_u/f64', 'b1'), + ('f32.convert_s/i32', 'b2'), + ('f32.convert_u/i32', 'b3'), + ('f32.convert_s/i64', 'b4'), + ('f32.convert_u/i64', 'b5'), + ('f32.demote/f64', 'b6'), + ('f64.convert_s/i32', 'b7'), + ('f64.convert_u/i32', 'b8'), + ('f64.convert_s/i64', 'b9'), + ('f64.convert_u/i64', 'ba'), + ('f64.promote/f32', 'bb')] + conversion_dict = dict(conversion) + conversion_dict_rev = {v: k for k, v in conversion_dict.items()} + + reinterpretations = [('i32.reinterpret/f32', 'bc'), + ('i64.reinterpret/f64', 'bd'), + ('f32.reinterpret/i32', 'be'), + ('f64.reinterpret/i64', 'bf')] + reinterpretations_dict = dict(reinterpretations) + reinterpretations_dict_rev = {v: k for k, + v in reinterpretations_dict.items()} + + section_code = [('type', '01'), ('import', '02'), + ('function', '03'), ('table', '04'), + ('memory', '05'), ('global', '06'), + ('export', '07'), ('start', '08'), + ('element', '09'), ('code', '0a'), + ('data', '0b'), ('custom', '00')] + section_code_dict = dict(section_code) + section_code_dict_rev = {v: k for k, v in section_code_dict.items()} diff --git a/parse.py b/parse.py new file mode 100755 index 0000000..ff28b8a --- /dev/null +++ b/parse.py @@ -0,0 +1,1031 @@ +#!/bin/python3 + +from __future__ import print_function +import argparse +import sys +import re +from section_structs import * +from utils import * +from opcodes import * +from copy import deepcopy +from init import * +import readline +import code +import signal + +_DBG_ = True + +def SigHandler_SIGINT(signum, frame): + print() + sys.exit(0) + +# we first read the object file and put all the sections in this class +class ParsedStruct: + def __init__(self): + self.version_number = int() + self.section_list = [] + + +# like the above. currently unused +class ParsedStructV2: + def __init__(self, version_number, section_list): + self.version_number = version_number + self.section_list = section_list + + +# @DEVI-Deprecated-convert a bytearray to int +def Conver2Int(little_endian, size, bytelist): + modifier = size - 1 + sum = 0 + + if little_endian: + for bit in reversed(bytelist): + if bit != 0x80: + sum += bit*(pow(16, modifier)) + modifier -= 1 + return(sum) + else: + for bit in reversed(bytelist): + if bit != 0x80: + sum += bit*(pow(16, modifier)) + modifier -= 1 + return(sum) + +# the argparser +class Argparser(object): + def __init__(self): + parser = argparse.ArgumentParser() + parser.add_argument("--wast", type=str, help="path to the wasm text file") + parser.add_argument("--wasm", type=str, nargs='+', help="path to the wasm object file") + parser.add_argument("--asb", type=str, help="path to the wast file to assemble") + parser.add_argument("--dis", type=str, help="path to the wasm file to disassemble") + parser.add_argument("-o", type=str, help="the path to the output file") + parser.add_argument("--dbg", action='store_true', help="print debug info", default=False) + parser.add_argument("--unval", action='store_true', help="skips validation tests", default=False) + parser.add_argument("--memdump", type=int, help="dumps the linear memory") + parser.add_argument("--idxspc", action='store_true', help="print index space data", default=False) + parser.add_argument("--run", action='store_true', help="runs the start function", default=False) + parser.add_argument("--metric", action='store_true', help="print metrics", default=False) + parser.add_argument("--gas", action='store_true', help="print gas usage", default=False) + parser.add_argument("--entry", type=str, help="name of the function that will act as the entry point into execution") + parser.add_argument("--link", type=str, nargs="+", help="link the following wasm modules") + parser.add_argument("--sectiondump", type=str, help="dumps the section provided") + parser.add_argument("--hexdump", type=int, help="dumps all sections") + parser.add_argument("--dbgsection", type=str, help="dumps the parsed section provided", default="") + parser.add_argument("--interactive", action='store_true', help="open in cli mode", default=False) + parser.add_argument("--rawdump", type=int, nargs=2, help="dumps all sections") + self.args = parser.parse_args() + if self.args.wasm is not None and self.args.wast is not None: + raise Exception("the --wast option and the --wasm option cannot\ + be set at the same time. you need to choose one.") + + def getParseFlags(self): + return(ParseFlags(self.args.wast, self.args.wasm, self.args.asb, self.args.dis, + self.args.o, self.args.dbg, self.args.unval, self.args.memdump, + self.args.idxspc, self.args.run, self.args.metric, self.args.gas, self.args.entry)) + +# reads a wasm-obj file, returns a parsedstruct that holds all the sections' +# bytecode, their section type and their length +def ReadWASM(file_path, endianness, is_extended_isa, dbg): + temp_obj_file = [] + wasm_file = open(file_path, "rb") + parsedstruct = ParsedStruct() + # read the magic cookie + byte = wasm_file.read(WASM_OP_Code.uint32) + if byte != WASM_OP_Code.magic_number.to_bytes(WASM_OP_Code.uint32, byteorder=endianness, signed=False): + raise Exception("bad magic cookie") + + # read the version number + byte = wasm_file.read(WASM_OP_Code.uint32) + if byte != WASM_OP_Code.version_number.to_bytes(WASM_OP_Code.uint32, byteorder=endianness, signed=False): + raise Exception("bad version number") + else: + parsedstruct.version_number = byte + + while True: + byte = wasm_file.read(1) + if byte != b'': + temp_obj_file.append(int.from_bytes(byte, byteorder='big', signed=False)) + else: + break + + offset = 0 + loop = True + while loop: + try: + # section_id, offset, dummy = Read(temp_obj_file, offset, 'varuint7') + section_id, offset, dummy = Read(temp_obj_file, offset, 'varuint32') + except IndexError: + break + + payload_length, offset, dummy = Read(temp_obj_file, offset, 'varuint32') + + if section_id == 0: + is_custom_section = True + name_len, offset, dummy = Read(temp_obj_file, offset, 'varuint32') + name = temp_obj_file[offset : offset + name_len] + offset += name_len + if name.find("reloc", 0, 5) == 0: + is_reloc_section = True + reloc_entry_count = Read(temp_obj_file, offset, 'varuint32') + for i in range(0, reloc_entry_count): + reloc_entry, offset, dummy = Read(tmp_obj, offset, 'varuint32') + reloc_entries.append(reloc_entry) + else: + is_custom_section = False + name_len = 0 + name = '' + dummy = 0 + + payload_data = temp_obj_file[offset:offset + payload_length - name_len - dummy] + offset += payload_length - name_len - dummy + + # @DEVI-the second field is for general use. it is unused right + # now so we are filling it with jojo. + parsedstruct.section_list.append([section_id, 'jojo', payload_length, is_custom_section, name_len, name, payload_data]) + + # prints out the sections in the wasm object + for section in parsedstruct.section_list: + pass + #print(section) + wasm_file.close() + return(parsedstruct) + +# Receives a parsedstruct returned from ReadWASM, parses all the sections and +# fills up a module class. the parse method, then can return the module. +# the returned class objects are all defined in section_structs.py. +class ObjReader(object): + def __init__(self, parsedstruct): + self.parsedstruct = parsedstruct + + # we use this method to read the operands of instructions. it's only + # called by ReadCodeSection + def Disassemble(self, section_byte, offset): + # @DEVI-FIXME- not sure why i was using instruction. its a string... + matched = False + read_bytes = 0 + read_bytes_temp = 0 + read_bytes_temp_iter = 0 + instruction = str() + operands = [] + temp_wasm_ins = WASM_Ins() + + # @DEVI-FIXME-for v1.0 opcodes. needs to get fixed for extended + # op-codes. ideally the mosule should hold its version number so we can + # check it here. + byte = format(section_byte[6][offset], '02x') + offset += 1 + read_bytes += 1 + + for op_code in WASM_OP_Code.all_ops: + if op_code[1] == byte: + matched = True + + # br_table has special immediates + # @DEVI-FIXME-this is costing us quite dearly for every opcode + # we read(at least two ticks per opcode). I could have the + # br_table opcode done separately but kinda hurts the codes + # uniformity. anyways. + if op_code[1] == '0e': + matched = True + temp, offset, read_bytes_temp_iter = Read(section_byte[6], offset, op_code[3][0]) + instruction += repr(temp) + ' ' + operands.append(repr(temp)) + read_bytes_temp += read_bytes_temp_iter + for target_table in range(0, temp): + temp, offset, read_bytes_temp_iter = Read(section_byte[6], offset, op_code[3][1]) + read_bytes_temp += read_bytes_temp_iter + instruction += repr(temp) + ' ' + operands.append(repr(temp)) + temp, offset, read_bytes_temp_iter = Read(section_byte[6], offset, op_code[3][2]) + instruction += repr(temp) + ' ' + operands.append(repr(temp)) + read_bytes_temp += read_bytes_temp_iter + elif op_code[2]: + if isinstance(op_code[3], tuple): + for i in range(0, len(op_code [3])): + temp, offset, read_bytes_temp_iter = Read(section_byte[6], offset, op_code[3][i]) + read_bytes_temp += read_bytes_temp_iter + instruction += repr(temp) + ' ' + operands.append(repr(temp)) + else: + temp, offset, read_bytes_temp = Read(section_byte[6], offset, op_code[3]) + instruction += repr(temp) + operands.append(repr(temp)) + + temp_wasm_ins.opcode = op_code[0] + temp_wasm_ins.opcodeint = int(byte, 16) + #temp_wasm_ins.operands = instruction + temp_wasm_ins.operands = operands + instruction = str() + operands = [] + break + + read_bytes += read_bytes_temp + return offset, matched, read_bytes, temp_wasm_ins + + # parses the code section. returns a Code_Section class + def ReadCodeSection(self): + offset = 0 + CS = Code_Section() + temp_func_bodies = Func_Body() + temp_local_entry = Local_Entry() + section_exists = False + for whatever in self.parsedstruct.section_list: + # 10 is the code section + if whatever[0] == 10: + code_section = whatever.copy() + section_exists = True + + if not section_exists: + return None + + fn_cn, offset, dummy = Read(code_section[6], offset, 'varuint32') + function_cnt = fn_cn + CS.count = function_cnt + + while function_cnt > 0: + function_body_length, offset, dummy = Read(code_section[6], offset, 'varuint32') + temp_func_bodies.body_size = function_body_length + + local_count, offset, dummy = Read(code_section[6], offset, 'varuint32') + temp_func_bodies.local_count = local_count + + # local_count_size will eventually hold how many bytes we will read + # in total because of the local section + local_count_size = dummy + if local_count != 0: + for i in range(0, local_count): + partial_local_count, offset, dummy = Read(code_section[6], offset, 'varuint32') + local_count_size += dummy + partial_local_type, offset, dummy = Read(code_section[6], offset, 'uint8') + local_count_size += dummy + temp_local_entry.count = partial_local_count + temp_local_entry.type = partial_local_type + temp_func_bodies.locals.append(deepcopy(temp_local_entry)) + local_count -= partial_local_count + else: + pass + + read_bytes_so_far = local_count_size + for i in range(0, function_body_length - local_count_size): + offset, matched, read_bytes, temp_wasm_ins = self.Disassemble(code_section, offset) + temp_func_bodies.code.append(deepcopy(temp_wasm_ins)) + + if not matched: + print(Colors.red + 'did not match anything' + Colors.ENDC) + print(Colors.red + 'code section offset: ' + repr(offset) + Colors.ENDC) + print(Colors.red + 'read bytes: ' + repr(read_bytes) + Colors.ENDC) + print(Colors.red + 'wasm ins: ' + repr(temp_wasm_ins.opcode) + Colors.ENDC) + + for iter in temp_func_bodies.code: + print(iter.opcode) + print(iter.operands) + sys.exit(1) + else: + pass + matched = False + read_bytes_so_far += read_bytes + if read_bytes_so_far == function_body_length: + break + + CS.func_bodies.append(deepcopy(temp_func_bodies)) + temp_func_bodies.locals = [] + temp_func_bodies.code = [] + function_cnt -= 1 + return(CS) + + # parsed the data section. returns a Data_Section class + def ReadDataSection(self): + loop = True + section_exists = False + offset = 0 + DS = Data_Section() + temp_data_segment = Data_Segment() + init_expr = [] + for whatever in self.parsedstruct.section_list: + if whatever[0] == 11: + data_section = whatever.copy() + section_exists = True + + if not section_exists: + return None + + data_entry_count, offset, dummy = Read(data_section[6], offset, 'varuint32') + DS.count = data_entry_count + + while data_entry_count != 0: + linear_memory_index, offset, dummy = Read(data_section[6], offset, 'varuint32') + temp_data_segment.index = linear_memory_index + + # reading in the init-expr + while loop: + # @DEVI-FIXME-this only works for none extended opcodes + if data_section[6][offset] == 0x0b: + loop = False + data_char, offset, dummy = Read(data_section[6], offset, 'uint8') + init_expr.append(data_char) + + temp_data_segment.offset = init_expr + + data_entry_length, offset, dummy = Read(data_section[6], offset, 'varuint32') + temp_data_segment.size = data_entry_length + + data_itself = data_section[6][offset:offset + data_entry_length] + temp_data_segment.data = data_itself + offset += data_entry_length + + DS.data_segments.append(deepcopy(temp_data_segment)) + + data_entry_count -= 1 + init_expr = [] + loop = True + return(DS) + + # parses the import section. returns an Import_Section class + def ReadImportSection(self): + offset = 0 + section_exists = False + module_name = [] + field_name = [] + IS = Import_Section() + temp_import_entry = Import_Entry() + for whatever in self.parsedstruct.section_list: + if whatever[0] == 2: + import_section = whatever.copy() + section_exists = True + + if not section_exists: + return None + + import_cnt, offset, dummy = Read(import_section[6], offset, 'varuint32') + IS.count = import_cnt + + while import_cnt != 0: + module_length, offset, dummy = Read(import_section[6], offset, 'varuint32') + temp_import_entry.module_len = module_length + + for i in range(0, module_length): + module_name.append(import_section[6][offset + i]) + temp_import_entry.module_str = module_name + offset += module_length + + field_length, offset, dummy = Read(import_section[6], offset, 'varuint32') + temp_import_entry.field_len = field_length + for i in range(0, field_length): + field_name.append(import_section[6][offset + i]) + temp_import_entry.field_str = field_name + offset += field_length + + kind, offset, dummy = Read(import_section[6], offset, 'uint8') + temp_import_entry.kind = kind + + # function type + if kind == 0: + import_type, offset, dummy = Read(import_section[6], offset, 'varuint32') + temp_import_entry.type = import_type + # table type + elif kind == 1: + table_type = Table_Type() + table_type.elemet_type, offset, dummy = Read(import_section[6], offset, 'varint7') + rsz_limits = Resizable_Limits() + rsz_limits.flags, offset, dummy = Read(import_section[6], offset, 'varuint1') + rsz_limits.initial, offset, dummy = Read(import_section[6], offset, 'varuint32') + if rsz_limits.flags: + rsz_limits.maximum, offset, dummy = Read(import_section[6], offset, 'varuint32') + table_type.limit = rsz_limits + temp_import_entry.type = table_type + elif kind == 2: + memory_type = Memory_Type() + rsz_limits = Resizable_Limits() + rsz_limits.flags, offset, dummy = Read(import_section[6], offset, 'varuint1') + rsz_limits.initial, offset, dummy = Read(import_section[6], offset, 'varuint32') + if rsz_limits.flags: + rsz_limits.maximum, offset, dummy = Read(import_section[6], offset, 'varuint32') + memory_type.limits = rsz_limits + temp_import_entry.type = memory_type + elif kind == 3: + global_type = Global_Type() + global_type.content_type, offset, dummy = Read(import_section[6], offset, 'uint8') + global_type.mutability, offset, dummy = Read(import_section[6], offset, 'varuint1') + temp_import_entry.type = global_type + + IS.import_entry.append(deepcopy(temp_import_entry)) + + import_cnt -= 1 + module_name = [] + field_name = [] + return(IS) + + # parses the export section, returns an Export_Section class + def ReadExportSection(self): + offset = 0 + section_exists = False + field_name = [] + ES = Export_Section() + temp_export_entry = Export_Entry() + for whatever in self.parsedstruct.section_list: + if whatever[0] == 7: + export_section = whatever.copy() + section_exists = True + + if not section_exists: + return None + + export_entry_cnt, offset, dummy = Read(export_section[6], offset, 'varuint32') + ES.count = export_entry_cnt + + while export_entry_cnt != 0: + field_length, offset, dummy = Read(export_section[6], offset, 'varuint32') + temp_export_entry.field_len = field_length + + for i in range(0, field_length): + field_name.append(export_section[6][offset + i]) + temp_export_entry.fiels_str = field_name + offset += field_length + + kind, offset, dummy = Read(export_section[6], offset, 'uint8') + temp_export_entry.kind = kind + + index, offset, dummy = Read(export_section[6], offset, 'varuint32') + temp_export_entry.index = index + + ES.export_entries.append(deepcopy(temp_export_entry)) + + export_entry_cnt -= 1 + field_name = [] + return(ES) + + # parses the type section, returns a Type_Section class + def ReadTypeSection(self): + offset = 0 + section_exists = False + param_list = [] + return_list = [] + TS = Type_Section() + temp_func_type = Func_Type() + for whatever in self.parsedstruct.section_list: + if whatever[0] == 1: + type_section = whatever.copy() + section_exists = True + + if not section_exists: + return None + + type_entry_count, offset, dummy = Read(type_section[6], offset, 'varuint32') + TS.count = type_entry_count + + while type_entry_count != 0: + form, offset, dummy = Read(type_section[6], offset, 'varint7') + temp_func_type.form = form + + param_count, offset, dummy = Read(type_section[6], offset, 'varuint32') + temp_func_type.param_cnt = param_count + + for i in range(0, param_count): + param_list.append(type_section[6][offset + i]) + temp_func_type.param_types = param_list + offset += param_count + + # @DEVI-FIXME- only works for MVP || single return value + return_count, offset, dummy = Read(type_section[6], offset, 'varuint1') + temp_func_type.return_cnt = return_count + + for i in range(0, return_count): + return_list.append(type_section[6][offset + i]) + temp_func_type.return_type = return_list + offset += return_count + + TS.func_types.append(deepcopy(temp_func_type)) + + type_entry_count -= 1 + param_list = [] + return_list = [] + return(TS) + + # parses the function section, returns a Function_section class + def ReadFunctionSection(self): + offset = 0 + section_exists = False + index_to_type = [] + FS = Function_Section() + for whatever in self.parsedstruct.section_list: + if whatever[0] == 3: + function_section = whatever.copy() + section_exists = True + + if not section_exists: + return None + + function_entry_count, offset, dummy = Read(function_section[6], offset, 'varuint32') + FS.count = function_entry_count + + for i in range(0, function_entry_count): + index, offset, dummy = Read(function_section[6], offset, 'varuint32') + index_to_type.append(index) + FS.type_section_index = index_to_type + offset += function_entry_count + return(FS) + + # parses the element secction, returns an Element_Section class + def ReadElementSection(self): + offset = 0 + section_exists = False + init_expr = [] + loop = True + function_indices = [] + ES = Element_Section() + temp_elem_segment = Elem_Segment() + + for whatever in self.parsedstruct.section_list: + if whatever[0] == 9: + element_section = whatever.copy() + section_exists = True + + if not section_exists: + return None + + element_entry_count, offset, dummy = Read(element_section[6], offset, 'varuint32') + ES.count = element_entry_count + + while element_entry_count != 0: + table_index, offset, dummy = Read(element_section[6], offset, 'varuint32') + temp_elem_segment.index = table_index + + # @DEVI-FIXME-only works for non-extneded opcodes + while loop: + if element_section[6][offset] == 0x0b: + loop = False + init_expr.append(element_section[6][offset]) + offset += 1 + temp_elem_segment.offset = init_expr + + num_elements, offset, dummy = Read(element_section[6], offset, 'varuint32') + temp_elem_segment.num_elem = num_elements + + for i in range(0, num_elements): + index, offset, dummy = Read(element_section[6], offset, 'varuint32') + function_indices.append(index) + temp_elem_segment.elems = function_indices + offset += num_elements + + ES.elem_segments.append(deepcopy(temp_elem_segment)) + + loop = True + init_expr = [] + function_indices = [] + element_entry_count -= 1 + return(ES) + + # parses the memory section, returns a Memory_Section class + def ReadMemorySection(self): + offset = 0 + section_exists = False + MS = Memory_Section() + temp_rsz_limits = Resizable_Limits() + + for whatever in self.parsedstruct.section_list: + if whatever[0] == 5: + memory_section = whatever.copy() + section_exists = True + + if not section_exists: + return None + + num_linear_mems, offset, dummy = Read(memory_section[6], offset, 'varuint32') + MS.count = num_linear_mems + + while num_linear_mems != 0: + flag, offset, dummy = Read(memory_section[6], offset, 'varuint1') + temp_rsz_limits.flags = flag + + initial,offset, dummy = Read(memory_section[6], offset, 'varuint32') + temp_rsz_limits.initial = initial + + if flag: + maximum, offset, dummy = Read(memory_section[6], offset, 'varuint32') + temp_rsz_limits.maximum = maximum + + MS.memory_types.append(deepcopy(temp_rsz_limits)) + num_linear_mems -= 1 + return(MS) + + # parses the table section, returns a Table_Section class + def ReadTableSection(self): + offset = 0 + section_exists = False + TS = Table_Section() + temp_table_type = Table_Type() + temp_rsz_limits = Resizable_Limits() + + for whatever in self.parsedstruct.section_list: + if whatever[0] == 4: + table_section = whatever.copy() + section_exists = True + + if not section_exists: + return None + + table_count, offset, dummy = Read(table_section[6], offset, 'varuint32') + TS.count = table_count + + while table_count != 0: + element_type, offset, dummy = Read(table_section[6], offset, 'varint7') + temp_table_type.element_type = element_type + + flag, offset, dummy = Read(table_section[6], offset, 'varuint1') + temp_rsz_limits.flags = flag + + initial, offset, dummy = Read(table_section[6], offset, 'varuint32') + temp_rsz_limits.initial = initial + + if flag: + maximum, offset, dummy = Read(table_section[6], offset, 'varuint32') + temp_rsz_limits.maximum = maximum + + temp_table_type.limit = temp_rsz_limits + TS.table_types.append(deepcopy(temp_table_type)) + + table_count -= 1 + return(TS) + + # parses the global section, returns a Global_Section class + def ReadGlobalSection(self): + offset = 0 + loop = True + section_exists = False + init_expr = [] + GS = Global_Section() + temp_gl_var = Global_Variable() + temp_gl_type = Global_Type() + + for whatever in self.parsedstruct.section_list: + if whatever[0] == 6: + global_section = whatever.copy() + section_exists = True + + if not section_exists: + return None + + count, offset, dummy = Read(global_section[6], offset, 'varuint32') + GS.count = count + + while count != 0: + content_type, offset, dummy = Read(global_section[6], offset, 'uint8') + temp_gl_type.content_type = content_type + + mutability, offset, dummy = Read(global_section[6], offset, 'varuint1') + temp_gl_type.mutability = mutability + + # @DEVI-FIXME-only works for non-extended opcodes + while loop: + if global_section[6][offset] == 0x0b: + loop = False + init_expr.append(global_section[6][offset]) + offset += 1 + temp_gl_var.init_expr = init_expr + + temp_gl_var.global_type = temp_gl_type + GS.global_variables.append(deepcopy(temp_gl_var)) + + + count -= 1 + loop = True + init_expr = [] + return(GS) + + # parses the start section, returns a Start_Section + def ReadStartSection(self): + offset = 0 + section_exists = False + SS = Start_Section() + + for whatever in self.parsedstruct.section_list: + if whatever[0] == 8: + start_section = whatever.copy() + section_exists = True + if not section_exists: + return None + + function_index, offset, dummy = Read(start_section[6], offset, 'varuint32') + SS.function_section_index = function_index + return(SS) + + def ReadRelocationSection(self): + offset = 0 + section_exists = False + RS = Relocation_Section() + for whatever in self.parsedstruct.section_list: + if whatever[0] == 0 and whatever[1] == "reloc": + reloc_section = whatever.copy() + section_exists = True + if not section_exists: + return None + return(RS) + + def ReadNameSection(self): + offset = 0 + section_exists = False + NS = Name_Section() + for whatever in self.parsedstruct.section_list: + if whatever[0] == 0 and whatever[1] == "name": + name_section = whatever.copy() + section_exists = True + if not section_exists: + return None + return(NS) + + def ReadLinkingSection(self): + pass + + def ReadLinkingDotSections(self): + pass + + # unused-returns the cursor location in the object file + def getCursorLocation(self): + return(self.wasm_file.tell()) + + # a convinience method-builds a module class and returns it + def parse(self): + return(Module(self.ReadTypeSection(), self.ReadImportSection(), + self.ReadFunctionSection(), self.ReadTableSection(), + self.ReadMemorySection(), self.ReadGlobalSection(), + self.ReadExportSection(), self.ReadStartSection(), + self.ReadElementSection(), self.ReadCodeSection(), + self.ReadDataSection())) + + +# WIP-basically how the assembler is constructed +class ParserV1(object): + def __init__(self, path): + self.path = path + + def run(self): + wasmtobj = WASMText(self.path) + # wasmtobj.test_print() + wasmtobj.RegExSearch() + wasmtobj.PrintTypeDict() + wasmtobj.PrintImportDict() + wasmtobj.PrintTableDict() + wasmtobj.PrintElemDict() + wasmtobj.PrintMemoryDict() + wasmtobj.PrintDataDict() + wasmtobj.PrintExportDict() + wasmtobj.PrintFuncDict() + wasmtobj.PrintElemDict() + wasmtobj.FuncParser() + wasmtobj.FuncParserTest() + + funcbodyparser = FuncBodyParser(wasmtobj.getFuncBodies()) + headerparser = FuncBodyParser(wasmtobj.getTypeHeader()) + + expr_stack = funcbodyparser.ParseBodyV3(False) + header_stack = headerparser.ParseBodyV3(True) + + wasm_codeemitter = WASM_CodeEmitter(expr_stack) + #wasm_codeemitter.Obj_Header_32() + #wasm_codeemitter.Dump_Obj_STDOUT() + + #wasm_codeemitter.SetNewStack(header_stack) + #wasm_codeemitter.EmitTypeHeader() + #wasm_codeemitter.PrintTypeHeaderObj() + + +# our interpreter class +class PythonInterpreter(object): + def __init__(self): + self.modules = [] + self.sections = [] + + # appends a module to the module list that PythonInterpreter has + def appendmodule(self, module): + self.modules.append(module) + + # returns the list of modules that we have parsed so far + def getmodules(self): + return(self.modules) + + def appendsection(self, section): + self.sections.append(section) + + def getsections(self): + return self.sections + + # convinience method.calls the ObjReader to parse a wasm obj file. + # returns a module class. + def parse(self, file_path): + section = ReadWASM(file_path, 'little', False, True) + self.appendsection(section) + parser = ObjReader(section) + return(parser.parse()) + + # dumps the object sections' info to stdout. pretty print. + def dump_sections(self, module, dbgsection): + all = False + if dbgsection == "": + all = True + print(Colors.blue + Colors.BOLD + + 'BEGENNING OF MODULE' + Colors.ENDC) + + # type_section + if module.type_section is not None and (dbgsection == "type" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Type Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('count: ' + repr(module.type_section.count)) + for iter in module.type_section.func_types: + print(Colors.cyan + 'form: ' + repr(iter.form) + Colors.ENDC) + print(Colors.green + 'param count: ' + repr(iter.param_cnt) + Colors.ENDC) + print(Colors.red + 'param types: ' + repr(iter.param_types) + Colors.ENDC) + print(Colors.purple + 'return count: ' + repr(iter.return_cnt) + Colors.ENDC) + print(Colors.yellow + 'return type: ' + repr(iter.return_type) + Colors.ENDC) + + # import_section + if module.import_section is not None and (dbgsection == "import" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Import Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('count: ' + repr(module.import_section.count)) + for iter in module.import_section.import_entry: + print(Colors.cyan + 'module length: ' + repr(iter.module_len) + Colors.ENDC) + print(Colors.green + 'module str: ' + repr(iter.module_str) + Colors.ENDC) + print(Colors.red + 'field length: ' + repr(iter.field_len) + Colors.ENDC) + print(Colors.purple + 'field str: ' + repr(iter.field_str) + Colors.ENDC) + print(Colors.yellow + 'kind: ' + repr(iter.kind) + Colors.ENDC) + print(Colors.grey + 'type: ' + repr(iter.type) + Colors.ENDC) + + # function_section + if module.function_section is not None and (dbgsection == "function" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Function Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('count: ' + repr(module.function_section.count)) + for iter in module.function_section.type_section_index: + print(Colors.cyan + 'type section index: ' + repr(iter) + Colors.ENDC) + + # table_section + if module.table_section is not None and (dbgsection == "table" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Table Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('count: ' + repr(module.table_section.count)) + for iter in module.table_section.table_types: + print(Colors.cyan + 'element type: ' + repr(iter.element_type) + Colors.ENDC) + print(Colors.green + 'Resizable_Limits:flags: ' + repr(iter.limit.flags) + Colors.ENDC) + print(Colors.red + 'Resizable_Limits:initial: ' + repr(iter.limit.initial) + Colors.ENDC) + print(Colors.purple + 'Resizable_Limits:maximum: ' + repr(iter.limit.maximum) + Colors.ENDC) + + # memory_section + if module.memory_section is not None and (dbgsection == "memory" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Memory Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('count: ' + repr(module.memory_section.count)) + for iter in module.memory_section.memory_types: + print(Colors.green + 'Resizable_Limits:flags: ' + repr(iter.flags) + Colors.ENDC) + print(Colors.red + 'Resizable_Limits:initial: ' + repr(iter.initial) + Colors.ENDC) + print(Colors.purple + 'Resizable_Limits:maximum: ' + repr(iter.maximum) + Colors.ENDC) + + # global_section + if module.global_section is not None and (dbgsection == "global" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Global Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('count: ' + repr(module.global_section.count)) + for iter in module.global_section.global_variables: + print(Colors.green + 'global type: ' + repr(iter.global_type) + Colors.ENDC) + print(Colors.red + 'init expr: ' + repr(iter.init_expr) + Colors.ENDC) + + # export_section + if module.export_section is not None and (dbgsection == "export" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Export Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('count: ' + repr(module.export_section.count)) + for iter in module.export_section.export_entries: + print(Colors.green + 'field length: ' + repr(iter.field_len) + Colors.ENDC) + print(Colors.red + 'field str: ' + repr(iter.field_str) + Colors.ENDC) + print(Colors.purple + 'kind: ' + repr(iter.kind) + Colors.ENDC) + print(Colors.cyan + 'index: ' + repr(iter.index) + Colors.ENDC) + + # start_section + if module.start_section is not None and (dbgsection == "start" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Start Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('start function index: ' + repr(module.start_section.function_section_index)) + + # element_section + if module.element_section is not None and (dbgsection == "element" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Element Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('count: ' + repr(module.element_section.count)) + for iter in module.element_section.elem_segments: + print(Colors.green + 'index: ' + repr(iter.index) + Colors.ENDC) + print(Colors.red + 'offset: ' + repr(iter.offset) + Colors.ENDC) + print(Colors.purple + 'num_elem: ' + repr(iter.num_elem) + Colors.ENDC) + print(Colors.cyan + 'elemes:' + repr(iter.elems) + Colors.ENDC) + + # code_section + if module.code_section is not None and (dbgsection == "code" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Code Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('count: ' + repr(module.code_section.count)) + for iter in module.code_section.func_bodies: + print(Colors.green + 'body size: ' + repr(iter.body_size) + Colors.ENDC) + print(Colors.red + 'local enrty count: ' + repr(iter.local_count) + Colors.ENDC) + for iterer in iter.locals: + print(Colors.blue + 'local count: ' + repr(iterer.count) + Colors.ENDC) + print(Colors.blue + 'local type: ' + repr(iterer.type) + Colors.ENDC) + for iterer in iter.code: + instruction = iterer.opcode + ' ' + repr(iterer.operands) + print(Colors.yellow + instruction + Colors.ENDC, end="") + print("\t", end="") + print(Colors.cyan + 'opcode: ' + repr(iterer.opcode) + Colors.ENDC, end="") + print("\t", end="") + print(Colors.grey + 'immediate: ' + repr(iterer.operands) + Colors.ENDC, end="") + print("\t", end="") + print(Colors.UNDERLINE + "num of operands: " + repr(len(iterer.operands)) + Colors.ENDC) + + # data_section + if module.data_section is not None and (dbgsection == "data" or all): + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print(Colors.blue + Colors.BOLD + 'Data Section:' + Colors.ENDC) + print(Colors.blue + '------------------------------------------------------' + Colors.ENDC) + print('count: ' + repr(module.data_section.count)) + for iter in module.data_section.data_segments: + print(Colors.green + 'index: ' + repr(iter.index) + Colors.ENDC) + print(Colors.red + 'offset: ' + repr(iter.offset) + Colors.ENDC) + print(Colors.purple + 'size: ' + repr(iter.size) + Colors.ENDC) + print(Colors.cyan + 'data:' + repr(iter.data) + Colors.ENDC) + + # palceholder for the validation tests + def runValidations(self): + modulevalidation = ModuleValidation(self.modules[0]) + return(modulevalidation.ValidateAll()) + +def premain(argparser): + interpreter = PythonInterpreter() + if argparser.args.wasm: + for file_path in argparser.args.wasm: + module = interpreter.parse(file_path) + print(type(module)) + interpreter.appendmodule(module) + if argparser.args.dbg or argparser.args.dbgsection: + interpreter.dump_sections(module, argparser.args.dbgsection) + if interpreter.runValidations(): + print(Colors.red + "validations are not implemented yet" + Colors.ENDC) + pass + else: + print(Colors.red + 'failed validation tests' + Colors.ENDC) + vm = VM(interpreter.getmodules()) + vm.setFlags(argparser.getParseFlags()) + ms = vm.getState() + if argparser.args.idxspc: + DumpIndexSpaces(ms) + if argparser.args.memdump: + DumpLinearMems(ms.Linear_Memory, argparser.getMEMDUMP()) + if argparser.args.run: + vm.run() + # merklizer = Merklizer(ms.Linear_Memory[0][0:512], module) + # treelength, hashtree = merklizer.run() + + if argparser.args.interactive: + variables = globals().copy() + variables.update(locals()) + shell = code.InteractiveConsole(variables) + shell.interact(banner="WASM python REPL") + if argparser.args.hexdump: + dumpprettysections(interpreter.getsections(), argparser.args.hexdump, "") + if argparser.args.sectiondump is not None: + dumpprettysections(interpreter.getsections(), 24, argparser.args.sectiondump) + if argparser.args.wast: + #print(argparser.getWASTPath()) + parser = ParserV1(argparser.getWASTPath()) + parser.run() + # WIP-the assmebler + if argparser.args.asb: + print("not implemented yet") + sys.exit(1) + # WIP-the disassmebler + if argparser.args.dis: + print("not implemented yet") + sys.exit(1) + +def main(): + argparser = Argparser() + if argparser.args.dbg: + try: + premain(argparser) + except Exception: + variables = globals().copy() + variables.update(locals()) + shell = code.InteractiveConsole(variables) + shell.interact(banner="DEVIWASM REPL") + else: + premain(argparser) + +if __name__ == "__main__": + main() diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..bcccca1 --- /dev/null +++ b/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/bash + +"./dwasm.py" --wasm ./test/injected.wasm --section code diff --git a/section_structs.py b/section_structs.py new file mode 100644 index 0000000..219f7ea --- /dev/null +++ b/section_structs.py @@ -0,0 +1,301 @@ +# contains the data classes we use to hold the information of a module +class WASM_SECTION(object): + def __init__(self): + self.section_id = int() + self.string = str() + self.payload_length = int() + self.is_custom_section = bool() + self.name_len = int() + self.name = str() + self.payload_data = bytes() + +class WASM_SEGMENT_INFO(): + def __int__(self): + self.count = int() + self.segments = [] + +class WASM_SEGMENT_INFO_SEGMENT(): + def __init__(self): + self.name_len = int() + self.name_data = str() + self.alignment = int() + self.flags = int() + +class WASM_COMDAT_INFO_SUB(): + def __init__(self): + self.count = int() + self.comdats = [] + +class COMDAT(): + def __init(self): + self.name_len = int() + self.name_str = str() + self.flags = int() + self.count = int() + self.comdat_syms = [] + +class COMDAT_SYM(): + def __init(self): + self.kind = int() + self.index = int() + +class WASM_COMDAT_KIND(): + WASM_COMDAT_DATA = 0 + WASM_COMDAT_FUNCTION = 1 + WASM_COMDAT_GLOBAL = 2 + +class WASM_INIT_FUNCS(): + def __init__(self): + self.count = int() + self.functions = [] + +class WASM_SYMBOL_TABLE(): + def __init__(self): + self.count = int() + self.syminfo = [] + +class SYM_INFO(): + def __init__(self): + self.kind = int() + self.flags = int() + +class SYM_INFO_FLAGS(): + WASM_SYM_BINDING_WEAK = 1 + WASM_SYM_BINDING_LOCAL = 2 + WASM_SYM_VISIBILITY_HIDDEN = 4 + WASM_SYM_UNDEFINED = 16 + + +class Rel_Entry(): + def __int__(self): + self.type = int() + self.offset = int() + self.index = int() + +class RelA_Entry(): + def __int__(self): + self.type = int() + self.offset = int() + self.index = int() + self.addend = int() + +class Relocation_Section(): + def __int__(self): + self.section_id = int() + self.name_length = int() + self.name = str() + self.count = int() + self.entries = int() + +class Func_Type(): + def __init__(self): + self.form = int() + self.param_cnt = int() + self.param_types = [] + self.return_cnt = int() + self.return_type = [] + +class Global_Type(): + def __init__(self): + self.content_type = int() + self.mutability = int() + +class Resizable_Limits(): + def __init__(self): + self.flags = int() + self.initial = int() + self.maximum = int() + +class Table_Type(): + def __init__(self): + self.element_type = int() + self.limit = Resizable_Limits() + +class External_Kind(): + def __init__(self): + self.Function = 0 + self.Table = 1 + self.Memory = 2 + self.Global = 3 + +class Memory_Type(): + def __init__(self): + self.limits = [Resizable_Limits()] + +# @DEVI-FIXME- +class Init_Expr(): + pass + +class Type_Section(): + def __init__(self): + self.count = [] + self.func_types = [] + +class Import_Entry(): + def __init__(self): + self.module_len = int() + self.module_str = [] + self.field_len = int() + self.field_str = [] + self.kind = int() + self.type = int() + +class Import_Section(): + def __init__(self): + self.count = [] + self.import_entry = [] + +class Function_Section(): + def __init__(self): + self.count = [] + self.type_section_index = [int()] + +class Table_Section(): + def __init__(self): + self.count = [] + self.table_types = [] + +class Memory_Section(): + def __init__(self): + self.count = [] + # Resizable_Limits + self.memory_types = [] + +class Global_Variable(): + def __init__(self): + self.global_type = Global_Type() + self.init_expr = [] + +class Global_Section(): + def __init__(self): + self.count = [] + # Global_Variable + self.global_variables = [] + +class Export_Entry(): + def __init__(self): + self.field_len = int() + self.field_str = [] + self.kind = int() + self.index = int() + +class Export_Section(): + def __init__(self): + self.count = [] + # Export_Entry + self.export_entries = [] + +class Start_Section(): + def __init__(self): + self.function_section_index = [] + +class Elem_Segment(): + def __init__(self): + self.index = int() + self.offset = [] + self.num_elem = int() + self.elems = [] + +class Element_Section(): + def __init__(self): + self.count = [] + # Elem_Segment + self.elem_segments = [] + +class Local_Entry(): + def __init__(self): + self.count = int() + self.type = int() + +class WASM_Ins(): + def __init__(self): + self.opcode = str() + self.opcodeint = int() + self.operands = [] + +class Func_Body(): + def __init__(self): + self.body_size = int() + self.local_count = int() + # Local_Entry + self.locals = [] + # WASM_Ins + self.code = [] + self.end = int() + +class Code_Section(): + def __init__(self): + self.count = [] + # Func_Body + self.func_bodies = [] + +class Data_Segment(): + def __init__(self): + self.index = int() + self.offset = [] + self.size = int() + self.data = [] + +class Data_Section(): + def __init__(self): + self.count = [] + # Data_Segment + self.data_segments = [] + +class Name_Type(): + Module = 0 + Function = 1 + Local = 2 + +class Name_Section_Entry(object): + def __init__(self, name_type, name_payload_len, name_payload_data): + self.name_type = name_type + self.name_payload_len = name_payload_len + self.name_payload_data = name_payload_data + +class Name_Section(object): + def __init__(self, name_section_entry): + self.name_section_entry = [] + self.name_section_entry = name_section_entry + +class Module_Name(object): + def __init__(self, name_len, name_str): + self.name_len = name_len + self.name_str = name_str + +class Naming(object): + def __init__(self, index, name_len, name_str): + self.index = index + self.name_len = name_len + self.name_str = name_str + +class Name_Map(object): + def __init__(self, count, naming): + self.count = count + self.naming = [] + self.naming = naming + +# the module class +class Module(): + def __init__(self, type_section, import_section, function_section, + table_section, memory_section, global_section, export_section, + start_section, element_section, code_section, data_section): + self.type_section = type_section + self.import_section = import_section + self.function_section = function_section + self.table_section = table_section + self.memory_section = memory_section + self.global_section = global_section + self.export_section = export_section + self.start_section = start_section + self.element_section = element_section + self.code_section = code_section + self.data_section = data_section + +''' +class RT_INS_CELL(object): + def __init__(self): + label : str + mnemonic : str + ops : list +''' diff --git a/test/injected.wasm b/test/injected.wasm new file mode 100644 index 0000000..59f492c Binary files /dev/null and b/test/injected.wasm differ diff --git a/test/linker/.depend b/test/linker/.depend new file mode 100644 index 0000000..9cb14ac --- /dev/null +++ b/test/linker/.depend @@ -0,0 +1,2 @@ +file0.o: file0.c file1.c +file1.o: file1.c diff --git a/test/linker/file0.c b/test/linker/file0.c new file mode 100644 index 0000000..5eb172b --- /dev/null +++ b/test/linker/file0.c @@ -0,0 +1,20 @@ +#include +#include +#include "file1.c" + +#define CODE_SECTION_0_0 "constant_0_0" +#define CODE_SECTION_0_1 "constant_0_1" +#define CODE_SECTION_0_2 "constant_0_2" +#define CODE_SECTION_0_3 "constant_0_3" +#define CODE_SECTION_0_4 "constant_0_4" + +int g_int_0_0 = 0; +int g_int_0_1 = 1; + +int dummy_f_0_0(int n) { + return n*4; +} + +int main (int argc, char** argv) { + return 123; +} diff --git a/test/linker/file1.c b/test/linker/file1.c new file mode 100644 index 0000000..233eaad --- /dev/null +++ b/test/linker/file1.c @@ -0,0 +1,25 @@ +#include +#include +#if 1 +void print(void) { + printf("external symbol"); +} +#endif + +#define CODE_SECTION_1_0 "constant_1_0" +#define CODE_SECTION_1_1 "constant_1_1" +#define CODE_SECTION_1_2 "constant_1_2" +#define CODE_SECTION_1_3 "constant_1_3" +#define CODE_SECTION_1_4 "constant_1_4" + +int g_int_1_0 = 10; +int g_int_1_1 = 11; + +int dummy_f_1_0(int n) { + if (n >= 1) return dummy_f_1_0(n-1) * n; + else return 1; +} + +int dymmy_f_1_1(int n) { + return n*2; +} diff --git a/test/linker/makefile b/test/linker/makefile new file mode 100644 index 0000000..1cc9413 --- /dev/null +++ b/test/linker/makefile @@ -0,0 +1,44 @@ +TARGET=file0 +CC=clang +CC?=clang +CC_FLAGS= +CC_EXTRA?= +CC_FLAGS+=$(CC_EXTRA) + +SRCS=$(wildcard *.c) +WASM=$(patsubst %.c, %.wasm, $(wildcard *.c)) + +.DEFAULT:all + +.PHONY:all clean help + +all:$(TARGET) wasmforce + +depend:.depend + +.depend:$(SRCS) + rm -rf .depend + $(CC) -MM $(CC_FLAGS) $^ > ./.depend + +-include ./.depend + +%.wasm:%.c + llvm-wasm $< + +wasmforce:$(WASM) + @echo forcing generation of wasm and wast + +.c.o: + $(CC) $(CC_FLAGS) -c $< -o $@ + +$(TARGET): $(TARGET).o + $(CC) $^ $(LD_FLAGS) -o $@ + +clean: + rm -f *.s *.wasm *.wast *.bc *.o *~ $(TARGET) + rm .depend + +help: + @echo "all is the default target" + @echo "there is delete." + @echo "there is clean." diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..69393b4 --- /dev/null +++ b/utils.py @@ -0,0 +1,425 @@ +from opcodes import * +import numpy as np +import struct as stc + +class ParseFlags: + def __init__(self, wast_path, wasm_path, as_path, disa_path, out_path, dbg, unval, memdump + , idxspc, run, metric, gas, entry): + self.wast_path = wast_path + self.wasm_path = wasm_path + self.as_path = as_path + self.disa_path = disa_path + self.out_path = out_path + self.dbg = dbg + self.unval = unval + self.memdump = memdump + self.idxspc = idxspc + self.run = run + self.metric = metric + self.gas = gas + self.entry = entry + +# pretty print +class Colors: + purple = '\033[95m' + blue = '\033[94m' + green = '\033[92m' + yellow = '\033[93m' + red = '\033[91m' + grey = '\033[1;37m' + darkgrey = '\033[1;30m' + cyan = '\033[1;36m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + +def LEB128UnsignedDecode(bytelist): + result = 0 + shift = 0 + for byte in bytelist: + result |= (byte & 0x7f) << shift + if (byte & 0x80) == 0: + break + shift += 7 + return(result) + +def LEB128SignedDecode(bytelist): + result = 0 + shift = 0 + for byte in bytelist: + result |= (byte & 0x7f) << shift + last_byte = byte + shift += 7 + if (byte & 0x80) == 0: + break + + if last_byte & 0x40: + result |= - (1 << shift) + + return(result) + +def LEB128UnsignedEncode(int_val): + if int_val < 0: + raise Exception("value must not be negative") + elif int_val == 0: + return bytes([0]) + + byte_array = bytearray() + while int_val: + byte = int_val & 0x7f + byte_array.append(byte | 0x80) + int_val >>= 7 + + byte_array[-1] ^= 0x80 + + return(byte_array) + + +def LEB128SignedEncode(int_val): + byte_array = bytearray() + while True: + byte = int_val & 0x7f + byte_array.append(byte | 0x80) + int_val >>= 7 + if (int_val == 0 and byte&0x40 == 0) or (int_val == -1 and byte&0x40): + byte_array[-1] ^= 0x80 + break + + return(byte_array) + +# @DEVI-FIXME-MVP-only-we currently inly support consts and get_global +# interprets the init-exprs +def init_interpret(expr): + offset = 0 + byte, offset, dummy = Read(expr, offset, 'uint8') + const = int() + + if byte == 65: + # @DEVI-FIXME-the spec says varint32, obviously we are not doing that + # since it will return neg values which are meningless and break things + const, offset, dummy = Read(expr, offset, 'varuint32') + elif byte == 66: + const, offset, dummy = Read(expr, offset, 'varint64') + elif byte == 67: + const, offset, dummy = Read(expr, offset, 'uint32') + elif byte == 68: + const, offset, dummy = Read(expr, offset, 'uint64') + elif byte == 35: + pass + else: + raise Exception(Colors.red + "illegal opcode for an MVP init expr." + Colors.ENDC) + + block_end, offset, dummy = Read(expr, offset, 'uint8') + if block_end != 11: + raise Exception(Colors.red + "init expr has no block end." + Colors.ENDC) + + return(const) + +# reads different-typed values from a byte array, takes in the bytearray, the +# current offset the read should be performed from and the kind of value that +# should be read. returns the read value as a decimal number, the updated +# offset and the number of bytes read +def Read(section_byte, offset, kind): + operand = [] + return_list = int() + read_bytes = 0 + + if kind == 'varuint1' or kind == 'varuint7' or kind == 'varuint32' or kind == 'varuint64': + while True: + byte = int(section_byte[offset]) + read_bytes += 1 + offset += 1 + + operand.append(byte) + + if byte == 0x80: + pass + elif byte & 0x80 != 0: + pass + else: + # we have read the last byte of the operand + break + + return_list = LEB128UnsignedDecode(operand) + operand = [] + elif kind == 'uint8' or kind == 'uint16' or kind == 'uint32' or kind == 'uint64': + byte = section_byte[offset: offset + TypeDic[kind]] + read_bytes += TypeDic[kind] + offset += TypeDic[kind] + operand.append(byte) + return_list = int.from_bytes(operand[0], byteorder='little', signed=False) + operand = [] + elif kind == 'varint1' or kind == 'varint7' or kind == 'varint32' or kind == 'varint64': + while True: + byte = int(section_byte[offset]) + read_bytes += 1 + offset += 1 + operand.append(byte) + # @DEVI-what happens when we decode a 56-bit value? + if byte == 0x80 or byte == 0xff: + pass + elif byte & 0x80 != 0: + pass + else: + # we have read the lasy byte of the operand + break + return_list = LEB128SignedDecode(operand) + operand = [] + return return_list, offset, read_bytes + +def ror(val, type_length, rot_size): + rot_size_rem = rot_size % type_length + return (((val >> rot_size_rem) & (2**type_length - 1)) | ((val & (2**rot_size_rem - 1)) << (type_length - rot_size_rem))) + +def rol(val, type_length, rot_size): + rot_size_rem = rot_size % type_length + return (((val << rot_size_rem) & (2**type_length - 1)) | ((val & ((2**type_length - 1) - (2**(type_length - rot_size_rem) - 1))) >> (type_length - rot_size_rem))) + +# @DEVI-these are here because i wanted to test them to make sure what i thik is +# happening is really happening +def reinterpretf32toi32(val): + return (stc.unpack("i", stc.pack("f" ,val))[0]) + +def reinterpretf64toi64(val): + return (stc.unpack("Q", stc.pack("d", val))[0]) + +def reinterpreti32tof32(val): + return (stc.unpack("f", stc.pack("i", val))[0]) + +def reinterpreti64tof64(val): + return (stc.unpack("d", stc.pack("Q", val))[0]) + +# @DEVI-FIXME +def clz(val, _type): + cnt = int() + if _type == 'uint32': + bits = np.uint32(val) + power = 31 + while power > -1: + if val & 2**power == 0: + cnt += 1 + else: + break + power -= 1 + elif _type == 'uint64': + bits = bin(np.uint64(val)) + power = 63 + while power > -1: + if val & 2**power == 0: + cnt += 1 + else: + break + power -= 1 + else: + raise Exception(Colors.red + "unsupported type passed to clz." + Colors.ENDC) + return cnt + + +# @DEVI-FIXME +def ctz(val, _type): + cnt = int() + power = int() + if _type == 'uint32': + bits = np.uint32(val) + while power < 32: + if val & 2**power == 0: + cnt += 1 + else: + break + power += 1 + elif _type == 'uint64': + bits = bin(np.uint64(val)) + while power < 64: + if val & 2**power == 0: + cnt += 1 + else: + break + power += 1 + else: + raise Exception(Colors.red + "unsupported type passed to ctz." + Colors.ENDC) + return cnt + +# @DEVI-FIXME +def pop_cnt(val, _type): + cnt = int() + power = int() + if _type == 'uint32': + bits = np.uint32(val) + while power < 32: + if val & 2**power != 0: + cnt += 1 + power += 1 + elif _type == 'uint64': + bits = bin(np.uint64(val)) + while power < 64: + if val & 2**power != 0: + cnt += 1 + power += 1 + else: + raise Exception(Colors.red + "unsupported type passed to pop_cnt." + Colors.ENDC) + return cnt + +def gen_label(label_stack): + counter += 1 + label_stack.append(counter) + +def dumpprettysections(sections_list, width, section_name): + line_counter = 0 + str_list = [] + module_counter = 0 + section_offset = 0 + for sections in sections_list: + print (Colors.cyan + Colors.BOLD + "module " + repr(module_counter) + Colors.ENDC) + for section in sections.section_list: + if section_name == "": pass + else: + if section_name != SectionID[section[0]]: + continue + print(Colors.green + Colors.BOLD + SectionID[section[0]] + " section" + Colors.ENDC) + #print(Colors.green + "length: " + Colors.blue + section[1] + Colors.ENDC) + print(Colors.green + "length: " + Colors.blue + repr(section[2]) + Colors.ENDC) + print(Colors.green + "is custom section: " + Colors.blue + repr(section[3]) + Colors.ENDC) + print(Colors.green + "name length: " + Colors.blue + repr(section[4]) + Colors.ENDC) + print(Colors.green + "name: " + Colors.blue + section[5] + Colors.ENDC) + print("\t", end="") + for offset in range(0, width): + if offset <= 15: + print(Colors.yellow + hex(offset) + " " + Colors.ENDC, end="") + else: + print(Colors.yellow + hex(offset) + " " + Colors.ENDC, end="") + print() + print(Colors.yellow + Colors.BOLD + hex(section_offset) + "\t" + Colors.ENDC, end="") + for byte in section[6]: + if line_counter == width: + section_offset += width + #print("\t\t", end="") + line_counter = 0 + for char in str_list: + print(Colors.green + "|" + Colors.ENDC, end="") + if ord(char) < 32: print(" ", end="") + else: print(char, end="") + str_list = [] + print() + print(Colors.yellow + Colors.BOLD + hex(section_offset) + "\t" + Colors.ENDC, end="") + print(format(byte, '02x') + " ", end="") + str_list.append(chr(byte)) + line_counter += 1 + #print(" ", end="") + for i in range(0, width - line_counter): print(" ", end="") + for char in str_list: + if ord(char) < 32: print(" ", end="") + else: print(char, end="") + print(Colors.green + "|" + Colors.ENDC, end="") + str_list = [] + line_counter = 0 + section_offset = 0 + print() + str_list = [] + line_counter = 0 + module_counter += 1 + section_offset = 0 + +def popcnt32(r1): + temp = r1 + temp = (temp & 0x55555555) + ((temp >> 1) & 0x55555555) + temp = (temp & 0x33333333) + ((temp >> 2) & 0x33333333) + temp = (temp & 0x0f0f0f0f) + ((temp >> 4) & 0x0f0f0f0f) + temp = (temp & 0x00ff00ff) + ((temp >> 8) & 0x00ff00ff) + temp = (temp & 0x0000ffff) + ((temp >> 16) & 0x0000ffff) + return temp + +def popcnt64(r1): + temp = r1 + temp = (temp & 0x5555555555555555) + ((temp >> 1) & 0x5555555555555555) + temp = (temp & 0x3333333333333333) + ((temp >> 2) & 0x3333333333333333) + temp = (temp & 0x0f0f0f0f0f0f0f0f) + ((temp >> 4) & 0x0f0f0f0f0f0f0f0f) + temp = (temp & 0x00ff00ff00ff00ff) + ((temp >> 8) & 0x00ff00ff00ff00ff) + temp = (temp & 0x0000ffff0000ffff) + ((temp >> 16) & 0x0000ffff0000ffff) + temp = (temp & 0x00000000ffffffff) + ((temp >> 32) & 0x00000000ffffffff) + return temp + +def clz32(r1): + if r1 == 0: return 32 + temp_r1 = r1 + n = 0 + if temp_r1 & 0xffff0000 == 0: + n += 16 + temp_r1 = temp_r1 << 16 + if temp_r1 & 0xff000000 == 0: + n += 8 + temp_r1 = temp_r1 << 8 + if temp_r1 & 0xf0000000 == 0: + n += 4 + temp_r1 = temp_r1 << 4 + if temp_r1 & 0xc0000000 == 0: + n += 2 + temp_r1 = temp_r1 << 2 + if temp_r1 & 0x8000000 == 0: + n += 1 + return n + +def clz64(r1): + if r1 == 0: return 64 + temp_r1 = r1 + n = 0 + if temp_r1 & 0xffffffff00000000 == 0: + n += 32 + temp_r1 = temp_r1 << 32 + if temp_r1 & 0xffff000000000000 == 0: + n += 16 + temp_r1 == temp_r1 << 16 + if temp_r1 & 0xff00000000000000 == 0: + n+= 8 + temp_r1 = temp_r1 << 8 + if temp_r1 & 0xf000000000000000 == 0: + n += 4 + temp_r1 = temp_r1 << 4 + if temp_r1 & 0xc000000000000000 == 0: + n += 2 + temp_r1 = temp_r1 << 2 + if temp_r1 & 0x8000000000000000 == 0: + n += 1 + return n + +def ctz32(r1): + if r1 == 0: return 32 + temp_r1 = r1 + n = 0 + if temp_r1 & 0x0000ffff == 0: + n += 16 + temp_r1 = temp_r1 >> 16 + if temp_r1 & 0x000000ff == 0: + n += 8 + temp_r1 = temp_r1 >> 8 + if temp_r1 & 0x0000000f == 0: + n += 4 + temp_r1 = temp_r1 >> 4 + if temp_r1 & 0x00000003 == 0: + n += 2 + temp_r1 = temp_r1 >> 2 + if temp_r1 & 0x00000001 == 0: + n += 1 + return n + +def ctz64(r1): + if r1 == 0: return 64 + temp_r1 = r1 + n = 0 + if temp_r1 & 0x00000000ffffffff == 0: + n += 32 + temp_r1 = temp_r1 >> 32 + if temp_r1 & 0x000000000000ffff == 0: + n += 16 + temp_r1 = temp_r1 >> 16 + if temp_r1 & 0x00000000000000ff == 0: + n += 8 + temp_r1 = temp_r1 >> 8 + if temp_r1 & 0x000000000000000f == 0: + n += 4 + temp_r1 = temp_r1 >> 4 + if temp_r1 & 0x0000000000000003 == 0: + n += 2 + temp_r1 = temp_r1 >> 2 + if temp_r1 & 0x0000000000000001 == 0: + n += 1 + return n -- cgit v1.2.3