#!/bin/python3 from __future__ import print_function import argparse import sys from section_structs import * from utils import * from opcodes import * from copy import deepcopy from init import * import code _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 type(name) == list: print(''.join([chr(elem) for elem in name])) name = ''.join([chr(elem) for elem in name]) else: print(name) 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 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): 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): 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.purple + "field str: " + "".join([chr(elem) for elem in iter.field_str]) + Colors.ENDC ) print(Colors.yellow + "kind: " + repr(iter.kind) + Colors.ENDC) print(Colors.grey + "type: " + repr(iter.type) + Colors.ENDC) if type(iter.type) == Table_Type: print("element_type: " + repr(iter.type.element_type)) print("limit: " + repr(iter.type.limit)) print("flags: " + repr(iter.type.limit.flags)) print("initial: " + repr(iter.type.limit.initial)) print("maximum: " + repr(iter.type.limit.maximum)) if type(iter.type) == Global_Type: print("value_type: " + repr(iter.type.content_type)) print("mutability: " + repr(iter.type.mutability)) if type(iter.type) == Memory_Type: print("flags: " + repr(iter.type.limits.flags)) print("flags: " + repr(iter.type.limits.initial)) print("flags: " + repr(iter.type.limits.maximum)) # 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 ) 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()