diff options
author | bloodstalker <thabogre@gmail.com> | 2018-06-26 10:36:55 +0000 |
---|---|---|
committer | bloodstalker <thabogre@gmail.com> | 2018-06-26 10:36:55 +0000 |
commit | 26e2a879bdefafee3bff0a41e1167cbf29b3ab3f (patch) | |
tree | 7107b6666e8f39c00bf34abc70eb47926789e5be | |
parent | Initial commit (diff) | |
download | dwasm-26e2a879bdefafee3bff0a41e1167cbf29b3ab3f.tar.gz dwasm-26e2a879bdefafee3bff0a41e1167cbf29b3ab3f.zip |
first commit
-rw-r--r-- | README.md | 0 | ||||
-rwxr-xr-x | dwasm.py | 33 | ||||
-rw-r--r-- | execute.py | 1056 | ||||
-rw-r--r-- | init.py | 415 | ||||
-rw-r--r-- | linker.py | 2 | ||||
-rw-r--r-- | opcodes.py | 332 | ||||
-rwxr-xr-x | parse.py | 1031 | ||||
-rwxr-xr-x | run.sh | 3 | ||||
-rw-r--r-- | section_structs.py | 301 | ||||
-rw-r--r-- | test/injected.wasm | bin | 0 -> 1313 bytes | |||
-rw-r--r-- | test/linker/.depend | 2 | ||||
-rw-r--r-- | test/linker/file0.c | 20 | ||||
-rw-r--r-- | test/linker/file1.c | 25 | ||||
-rw-r--r-- | test/linker/makefile | 44 | ||||
-rw-r--r-- | utils.py | 425 |
15 files changed, 3689 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/README.md 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)) @@ -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() @@ -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 Binary files differnew file mode 100644 index 0000000..59f492c --- /dev/null +++ b/test/injected.wasm 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 <stdio.h> +#include <inttypes.h> +#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 <stdio.h> +#include <inttypes.h> +#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 |