#!/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()