diff options
Diffstat (limited to '')
-rwxr-xr-x | bruiser/wasm/parse.py | 1030 |
1 files changed, 1030 insertions, 0 deletions
diff --git a/bruiser/wasm/parse.py b/bruiser/wasm/parse.py new file mode 100755 index 0000000..05c6465 --- /dev/null +++ b/bruiser/wasm/parse.py @@ -0,0 +1,1030 @@ +#!/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 TBInit 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) + 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() |