diff options
Diffstat (limited to 'bruiser')
| -rw-r--r-- | bruiser/bruiser-extra.h | 3 | ||||
| -rw-r--r-- | bruiser/bruiser.cpp | 36 | ||||
| -rw-r--r-- | bruiser/bruiser.h | 5 | ||||
| -rw-r--r-- | bruiser/executioner.h | 81 | ||||
| -rw-r--r-- | bruiser/lua-scripts/demo1.lua | 10 | ||||
| -rw-r--r-- | bruiser/lua-scripts/demo2.lua | 11 | ||||
| -rw-r--r-- | bruiser/wasm/OpCodes.py | 318 | ||||
| -rw-r--r-- | bruiser/wasm/TBInit.py | 415 | ||||
| -rwxr-xr-x | bruiser/wasm/dwasm.py | 1032 | ||||
| -rw-r--r-- | bruiser/wasm/execute.py | 1056 | ||||
| -rwxr-xr-x | bruiser/wasm/run.sh | 3 | ||||
| -rw-r--r-- | bruiser/wasm/section_structs.py | 278 | ||||
| -rw-r--r-- | bruiser/wasm/test/injected.wasm | bin | 0 -> 1313 bytes | |||
| -rw-r--r-- | bruiser/wasm/utils.py | 425 | 
14 files changed, 3590 insertions, 83 deletions
| diff --git a/bruiser/bruiser-extra.h b/bruiser/bruiser-extra.h index 4e7ce11..7ef9454 100644 --- a/bruiser/bruiser-extra.h +++ b/bruiser/bruiser-extra.h @@ -135,6 +135,9 @@ std::vector<std::string> LUA_FUNCS =    "freejmptable(",    "dumpjmptable(",    "ramdump(", +  "xsize()", +  "xclear()", +  "xmemusage()",    "_G",    "_VERSION",    "assert", diff --git a/bruiser/bruiser.cpp b/bruiser/bruiser.cpp index 42dbac7..2e1fa71 100644 --- a/bruiser/bruiser.cpp +++ b/bruiser/bruiser.cpp @@ -81,7 +81,7 @@ using namespace clang::tooling;  /**********************************************************************************************************************/  /*global vars*/  namespace { // start of anonymous namespace -  std::vector<std::pair<void*, std::string>> vptrs; +  std::vector<std::tuple<void*, std::string, uint32_t>> vptrs;    static llvm::cl::OptionCategory BruiserCategory("Empty");    std::vector<std::string> PushToLua; @@ -1465,7 +1465,7 @@ class LuaWrapper          std::cout << "xobj will be registered as " << YELLOW << xobj_name << NORMAL << ". " << "it is recommended to use a post- or pre-fix for the xobj names to avoid namespace pollution." "\n";          std::cout << GREEN << "pointer: " << BLUE << xobj.first << " " << GREEN << "size: " << BLUE << xobj.second << NORMAL << "\n";        } -      vptrs.push_back(std::make_pair(xobj.first, xobj_name)); +      vptrs.push_back(std::make_tuple(xobj.first, xobj_name, xobj.second));        return 0;      } @@ -1475,6 +1475,24 @@ class LuaWrapper        return 1;      } +    int BruiserLuaXObjDeallocate(lua_State* __ls) { +      int argc = lua_gettop(__ls); +      if (argc != 0) PRINT_WITH_COLOR_LB(RED, "discarding arg..."); +      deallocatedXObj(vptrs); +      vptrs.clear(); +      return 0; +    } + +    int BruiserLuaGetXMemSize(lua_State* __ls) { +      int argc = lua_gettop(__ls); +      int sum = 0; +      for (auto& iter : vptrs) { +        sum += std::get<2>(iter); +      } +      lua_pushinteger(__ls, sum); +      return 1; +    } +      int BruiserLuaCallX(lua_State* __ls) {        int numargs = lua_gettop(__ls);        if (numargs != 5) {PRINT_WITH_COLOR_LB(RED, "xcall: bad number of args. expected exactly five.");} @@ -1484,10 +1502,10 @@ class LuaWrapper        void* x_ptr;         if (lua_type(__ls, 4) == LUA_TNUMBER) { -        if (vptrs.size() - 1 > lua_tointeger(__ls, 4)) x_ptr = vptrs[lua_tointeger(__ls, 4)].first; +        if (vptrs.size() - 1 > lua_tointeger(__ls, 4)) x_ptr = std::get<0>(vptrs[lua_tointeger(__ls, 4)]);        } else if (lua_type(__ls, 4) == LUA_TSTRING) {          for (auto& iter : vptrs) { -          if (iter.second == lua_tostring(__ls ,4)) x_ptr = iter.first; +          if (std::get<1>(iter) == lua_tostring(__ls ,4)) x_ptr = std::get<0>(iter);          }        } else {          PRINT_WITH_COLOR_LB(RED, "argument 4 is neihter a number nor a string."); @@ -1614,10 +1632,10 @@ class LuaWrapper        }        lua_newtable(__ls);        for (auto& iter : vptrs) { -        if (Verbose) std::cout << CYAN << iter.second << NORMAL; -        lua_pushstring(__ls, iter.second.c_str()); -        if (Verbose) std::cout << " " << MAGENTA << (long int)iter.first << NORMAL <<"\n"; -        lua_pushinteger(__ls, (long int)iter.first); +        if (Verbose) std::cout << CYAN << std::get<1>(iter) << NORMAL; +        lua_pushstring(__ls, std::get<1>(iter).c_str()); +        if (Verbose) std::cout << " " << MAGENTA << std::get<0>(iter) << NORMAL <<"\n"; +        lua_pushinteger(__ls, (uint64_t)std::get<0>(iter));          lua_settable(__ls, -3);        }        return 1; @@ -2358,6 +2376,8 @@ int main(int argc, const char **argv) {      lua_register(LE.GetLuaState(), "dumpjmptable", &LuaDispatch<&LuaWrapper::BruiserDumpJumpTable>);      lua_register(LE.GetLuaState(), "ramdump", &LuaDispatch<&LuaWrapper::BruiserRamDump>);      lua_register(LE.GetLuaState(), "xsize", &LuaDispatch<&LuaWrapper::BruiserLuaGetXSize>); +    lua_register(LE.GetLuaState(), "xclear", &LuaDispatch<&LuaWrapper::BruiserLuaXObjDeallocate>); +    lua_register(LE.GetLuaState(), "xmemusage", &LuaDispatch<&LuaWrapper::BruiserLuaGetXMemSize>);      runloop.setLW(std::move(LW));      runloop.run(); diff --git a/bruiser/bruiser.h b/bruiser/bruiser.h index cda065b..72ea366 100644 --- a/bruiser/bruiser.h +++ b/bruiser/bruiser.h @@ -161,7 +161,10 @@ help CMDHelp[] = {    {"getjmptable", "getjmptable(size, code)", "get a table of all jumps", "", "returns a pointer to the head of the jump table linked-list as lightuserdata"},    {"freejmptable", "freejmptable(head)", "free the jmp table linked-list", "", "nothing"},    {"dumpjmptable", "dumpjmptable(head)", "dumps the jmp table linked-list", "", "nothing"}, -  {"ramdump", "ramdump(pid)", "dumps the ram", "", "ram contents"} +  {"ramdump", "ramdump(pid)", "dumps the ram", "", "ram contents"}, +  {"xsize", "xsize()", "returns the number of currently registered xobjs", "", "nothing"}, +  {"xclear", "xclear()", "deallocates all xobjs, freeing memory", "", "nothing"}, +  {"xmemusage", "xmemusage()", "returns how much memory the xobjcts are occupying", "", "total memory used by xobjects"}  };  /**********************************************************************************************************************/  /** diff --git a/bruiser/executioner.h b/bruiser/executioner.h index 4e17a81..1eb09f8 100644 --- a/bruiser/executioner.h +++ b/bruiser/executioner.h @@ -60,6 +60,14 @@ namespace { // start of anonymous namespace  int getMemorySize(void) {return MEMORY_SIZE;} +void emitByte(uint8_t _byte, std::vector<uint8_t>& _code) { +  _code.push_back(_byte); +} + +void emitBytes(std::vector<uint8_t>& _bytes, std::vector<uint8_t>& _code) { +  for (auto &iter : _bytes) {emitByte(iter, _code);} +} +  std::pair<void*, size_t> loadObjsInXMem(std::vector<uint8_t>& _obj_code) {    size_t code_size = _obj_code.size();    void* program_memory = alloc_writeable_memory(code_size); @@ -75,72 +83,13 @@ std::pair<void*, size_t> loadObjsInXMem(std::vector<uint8_t>& _obj_code) {    return std::make_pair(program_memory, code_size);  } -class Executioner { -  public: -    Executioner() {} - -#if 0 -    Executioner() { -      std::cout << RED << "vptrs size on executioner ctor: " << vptrs.size() << NORMAL << "\n"; -      this->vptrs.reserve(100); -      this->xvoidptrs.reserve(100); -    } -#endif - -#if 0 -    ~Executioner() { -      for (auto &iter : xvoidptrs) { -        if (iter != nullptr) { -          if (munmap(iter, sizeof(void*)) < 0) { -            perror("could not unmap vmemory."); -          } -        } -      } -    } -#endif - -  //private: -    //Executioner(const Executioner&); -    //Executioner& operator=(const Executioner&); -  //public: -    //Executioner(Executioner&& x) = default; -    //Executioner &operator=(Executioner&& x) = default; - -  public: - -    void emitByte(uint8_t _byte, std::vector<uint8_t>& _code) { -      _code.push_back(_byte); -    } - -    void emitBytes(std::vector<uint8_t>& _bytes, std::vector<uint8_t>& _code) { -      for (auto &iter : _bytes) {this->emitByte(iter, _code);} -    } - -#if 0 -    void pushvptr(void* _vptr, std::string _name, std::vector<std::pair<void*, std::string>>) { -      this->vptrs.push_back(std::make_pair(_vptr, _name)); -    } - -    std::pair<void*, std::string> getvptrbyindex(unsigned int _index) { -      if (this->vptrs.size() - 1 >= _index) { -        return this->vptrs[_index]; -      } -      return std::make_pair(nullptr, ""); -    } - -    std::pair<void*, std::string> getvptrbyname(const char* name) { -      for (auto &iter : this->vptrs) { -        if (std::strcmp(name, iter.second.c_str()) == 0) return iter; -        std::cout << "xobj name match\n"; -      } -      return std::make_pair(nullptr, ""); -    } -#endif - -  //private: -    //std::vector<std::pair<void*, std::string>> vptrs; -    //std::vector<void*> xvoidptrs; -}; +void deallocatedXObj(std::vector<std::tuple<void*, std::string, uint32_t>> _vptrs) { +  std::cout << GREEN << "deallocating xobjs..." << NORMAL << "\n"; +  for (auto& iter : _vptrs) { +    int res = munmap(std::get<0>(iter), std::get<2>(iter)); +    if (res != 0) PRINT_WITH_COLOR_LB(RED, "could not unmap xobjs."); +  } +}  /**********************************************************************************************************************/  /**********************************************************************************************************************/  class XGlobals { diff --git a/bruiser/lua-scripts/demo1.lua b/bruiser/lua-scripts/demo1.lua index 6f02860..964fd81 100644 --- a/bruiser/lua-scripts/demo1.lua +++ b/bruiser/lua-scripts/demo1.lua @@ -121,7 +121,7 @@ function printFuncSizes()    end  end -function main() +function demo1()    pwd()    printObjNames()    printObjSizes() @@ -209,8 +209,14 @@ local C_main_code = codeTableByName("'main'")    a = xobjlist()    print("the offset of quad and add2 is : ", a["quad"] - a["add2"]) +  mem_size = xmemusage() +  print("memory used "..mem_size) +  xclear() +  mem_size = xmemusage() +  print("memory used "..mem_size) +  end -main() +demo1()  -------------------------------------------------------------------------------------------------------------- diff --git a/bruiser/lua-scripts/demo2.lua b/bruiser/lua-scripts/demo2.lua index a5cf1af..73a177c 100644 --- a/bruiser/lua-scripts/demo2.lua +++ b/bruiser/lua-scripts/demo2.lua @@ -11,7 +11,7 @@ function get_jmp_type(val)    return "U"  end -function main() +function demo21()    xobj.getSO(elf_file)    local add2_code = xobj.codeTableByName_number("'add2'")    local sub2_code = xobj.codeTableByName_number("'sub2'") @@ -21,8 +21,6 @@ function main()    local quad_code = xobj.codeTableByName_number("'quad'")    local passthrough_code = xobj.codeTableByName_number("'passthrough'") -  --xobj.printFuncSizes() -    xobjregister(add2_code, "add2")    xobjregister(sub2_code, "sub2")    xobjregister(adddouble_code, "adddouble") @@ -32,7 +30,7 @@ function main()    xobjregister(passthrough_code, "passthrough")  end -function pretty_dump() +function demo22()    count = 0    local text_section = xobj.getTextSection(elf_exe)    io.write(colors("%{blue}".."    ".."\t".."00 ".."01 ".."02 ".."03 ".."04 ".."05 ".."06 ".."07 ".."08 ".."09 ".."0A ".."0B ".."0C ".."0D ".."0E ".."0F")) @@ -118,9 +116,10 @@ function get_jmp_table()  end  --main() -pretty_dump()  --test()  --jmp_t_test()  --integ_test() ---asm_rewriter_pretty() +asm_rewriter_pretty()  --dump_jmp_table() +demo21() +demo22() diff --git a/bruiser/wasm/OpCodes.py b/bruiser/wasm/OpCodes.py new file mode 100644 index 0000000..ce813b0 --- /dev/null +++ b/bruiser/wasm/OpCodes.py @@ -0,0 +1,318 @@ +from enum import Enum + +SectionID = {0:"custom", 1:"type", 2:"import", 3:"function", 4:"table", 5:"memory", 6:"global", 7:"export", 8:"start", 9:"element", 10:"code", 11:"data", 63:"unknown"} + +class RelocType(Enum): +    R_WEBASSEMBLY_FUNCTION_INDEX_LEB = 0 +    R_WEBASSEMBLY_TABLE_INDEX_SLEB = 1 +    R_WEBASSEMBLY_TABLE_INDEX_I32 = 2 +    R_WEBASSEMBLY_MEMORY_ADDR_LEB = 3 +    R_WEBASSEMBLY_MEMORY_ADDR_SLEB = 4 +    R_WEBASSEMBLY_MEMORY_ADDR_I32 = 5 +    R_WEBASSEMBLY_TYPE_INDEX_LEB = 6 +    R_WEBASSEMBLY_GLOBAL_INDEX_LEB = 7 + +class TypeType(Enum): +    none = 1 +    lebu = 2 +    lebs = 3 +    flot = 4 +    dobl = 5 + +TypeKS = [['uint8', 8, TypeType.none], ['uint16', 16, TypeType.none], +          ['uint32', 32, TypeType.none], ['uint64', 64, TypeType.none], +          ['varuint1', 1, TypeType.lebu], ['varuint7', 7, TypeType.lebu], +          ['varuint32', 32, TypeType.lebu], ['varuint64', 64, TypeType.lebu], +          ['varint1', 1, TypeType.lebs], ['varint7', 7, TypeType.lebs], +          ['varint32', 32, TypeType.lebs], ['varint64', 64, TypeType.lebs]] + +TypeDic = {'uint8': 1, 'uint16': 2, 'uint32': 4, 'uint64': 8, +           'varuint1': 1, 'varuint7': 1, 'varuint32': 4, 'varuint64': 8, +           'varint1': 1, 'varint7': 1, 'varint32': 4, 'varint64': 8} + +# holds the version 1.0 wasm opcodes and immediates +class WASM_OP_Code: +    version_number = 0x01 +    magic_number = 0x6d736100 +    PAGE_SIZE = 65536 +    uint8 = 1 +    uint16 = 2 +    uint32 = 4 +    uint64 = 8 +    varuint1 = 1 +    varuint7 = 1 +    varuint32 = 4 +    varuint64 = 8 +    varint1 = 1 +    varint7 = 1 +    varint32 = 4 +    varint64 = 8 +    floatt = 4 +    doublet = 8 + +    all_ops = [('i32', '7f', False), ('i64', '7e', False), ('f32', '7d', False), +                ('f64', '7c', False), ('anyfunc', '7b', False), +                ('func', '60', False), ('empty_block_type', '40', False), +                ('unreachable', '00', False), ('nop', '01', False), +                ('block', '02', True, ('varuint7')), +                ('loop', '03', True, ('varuint7')), +                ('if', '04', True, ('varuint7')), ('else', '05', False), +                ('end', '0b', False), ('br', '0c', True, ('varuint32')), +                ('br_if', '0d', True, ('varuint32')), +                ('br_table', '0e', True, ('varuint32', 'varuint32', 'varuint32')), +                ('return', '0f', False), ('call', '10', True, ('varuint32')), +                ('call_indirect', '11', True, ('varuint32', 'varuint1')), +                ('drop', '1a', False), ('select', '1b', False), +                ('get_local', '20', True, ('varuint32')), +                ('set_local', '21', True, ('varuint32')), +                ('tee_local', '22', True, ('varuint32')), +                ('get_global', '23', True, ('varuint32')), +                ('set_global', '24', True, ('varuint32')), +                ('i32.load', '28', True, ('varuint32', 'varuint32')), +                ('i64.load', '29', True, ('varuint32', 'varuint32')), +                ('f32.load', '2a', True, ('varuint32', 'varuint32')), +                ('f64.load', '2b', True, ('varuint32', 'varuint32')), +                ('i32.load8_s', '2c', True, ('varuint32', 'varuint32')), +                ('i32.load8_u', '2d', True, ('varuint32', 'varuint32')), +                ('i32.load16_s', '2e', True, ('varuint32', 'varuint32')), +                ('i32.load16_u', '2f', True, ('varuint32', 'varuint32')), +                ('i64.load8_s', '30', True, ('varuint32', 'varuint32')), +                ('i64.load8_u', '31', True, ('varuint32', 'varuint32')), +                ('i64.load16_s', '32', True, ('varuint32', 'varuint32')), +                ('i64.load16_u', '33', True, ('varuint32', 'varuint32')), +                ('i64.load32_s', '34', True, ('varuint32', 'varuint32')), +                ('i64.load32_u', '35', True, ('varuint32', 'varuint32')), +                ('i32.store', '36', True, ('varuint32', 'varuint32')), +                ('i64.store', '37', True, ('varuint32', 'varuint32')), +                ('f32.store', '38', True, ('varuint32', 'varuint32')), +                ('f64.store', '39', True, ('varuint32', 'varuint32')), +                ('i32.store8', '3a', True, ('varuint32', 'varuint32')), +                ('i32.store16', '3b', True, ('varuint32', 'varuint32')), +                ('i64.store8', '3c', True, ('varuint32', 'varuint32')), +                ('i64.store16', '3d', True, ('varuint32', 'varuint32')), +                ('i64.store32', '3e', True, ('varuint32', 'varuint32')), +                ('current_memory', '3f', True, ('varuint1')), +                ('grow_memory', '40', True, ('varuint1')), +                ('i32.const', '41', True, ('varint32')), +                ('i64.const', '42', True, ('varint64')), +                ('f32.const', '43', True, ('uint32')), +                ('f64.const', '44', True, ('uint64')), +                ('i32.eqz', '45', False), ('i32.eq', '46', False), +                ('i32.ne', '47', False), ('i32.lt_s', '48', False), +                ('i32.lt_u', '49', False), ('i32.gt_s', '4a', False), +                ('i32.gt_u', '4b', False), ('i32.le_s', '4c', False), +                ('i32.le_u', '4d', False), ('i32.ge_s', '4e', False), +                ('i32.ge_u', '4f', False), ('i64.eqz', '50', False), +                ('i64.eq', '51', False), ('i64.ne', '52', False), +                ('i64.lt_s', '53', False), ('i64.lt_u', '54', False), +                ('i64.gt_s', '55', False), ('i64.gt_u', '56', False), +                ('i64.le_s', '57', False), ('i64.le_u', '58', False), +                ('i64.ge_s', '59', False), ('i64.ge_u', '5a', False), +                ('f32.eq', '5b', False), ('f32.ne', '5c', False), +                ('f32.lt', '5d', False), ('f32.gt', '5e', False), +                ('f32.le', '5f', False), ('f32.ge', '60', False), +                ('f64.eq', '61', False), ('f64.ne', '62', False), +                ('f64.lt', '63', False), ('f64.gt', '64', False), +                ('f64.le', '65', False), ('f64.ge', '66', False), +                ('i32.clz', '67', False), ('i32.ctz', '68', False), +                ('i32.popcnt', '69', False), ('i32.add', '6a', False), +                ('i32.sub', '6b', False), ('i32.mul', '6c', False), +                ('i32.div_s', '6d', False), ('i32.div_u', '6e', False), +                ('i32.rem_s', '6f', False), ('i32.rem_u', '70', False), +                ('i32.and', '71', False), ('i32.or', '72', False), +                ('i32.xor', '73', False), ('i32.shl', '74', False), +                ('i32.shr_s', '75', False), ('i32.shr_u', '76', False), +                ('i32.rotl', '77', False), ('i32.rotr', '78', False), +                ('i64.clz', '79', False), ('i64.ctz', '7a', False), +                ('i64.popcnt', '7b', False), ('i64.add', '7c', False), +                ('i64.sub', '7d', False), ('i64.mul', '7e', False), +                ('i64.div_s', '7f', False), ('i64.div_u', '80', False), +                ('i64.rem_s', '81', False), ('i64.rem_u', '82', False), +                ('i64.and', '83', False), ('i64.or', '84', False), +                ('i64.xor', '85', False), ('i64.shl', '86', False), +                ('i64.shr_s', '87', False), ('i64.shr_u', '88', False), +                ('i64.rotl', '89', False), ('i63.rotr', '8a', False), +                ('f32.abs', '8b', False), ('f32.neg', '8c', False), +                ('f32.ceil', '8d', False),  ('f32.floor', '8e', False), +                ('f32.trunc', '8f', False), ('f32.nearest', '90', False), +                ('f32.sqrt', '91', False), ('f32.add', '92', False), +                ('f32.sub', '93', False), ('f32.mul', '94', False), +                ('f32.div', '95', False), ('f32.min', '96', False), +                ('f32.max', '97', False), ('f32.copysign', '98', False), +                ('f64.abs', '99', False), ('f64.neg', '9a', False), +                ('f64.ceil', '9b', False), ('f64.floor', '9c', False), +                ('f64.trunc', '9d', False), ('f64.nearest', '9e', False), +                ('f64.sqrt', '9f', False), ('f64.add', 'a0', False), +                ('f64.sub', 'a1', False), ('f64.mul', 'a2', False), +                ('f64.div', 'a3', False), ('f64.min', 'a4', False), +                ('f64.max', 'a5', False), ('f64.copysign', 'a6', False), +                ('i32.wrap/i64', 'a7', False), ('i32.trunc_s/f32', 'a8', False), +                ('i32.trunc_u/f32', 'a9', False), +                ('i32.trunc_s/f64', 'aa', False), +                ('i32.trunc_u/f64', 'ab', False), +                ('i64.extend_s/i32', 'ac', False), +                ('i64.extend_u/i32', 'ad', False), +                ('i64.trunc_s/f32', 'ae', False), +                ('i64.trunc_u/f32', 'af', False), +                ('i64.trunc_s/f64', 'b0', False), +                ('i64.trunc_u/f64', 'b1', False), +                ('f32.convert_s/i32', 'b2', False), +                ('f32.convert_u/i32', 'b3', False), +                ('f32.convert_s/i64', 'b4', False), +                ('f32.convert_u/i64', 'b5', False), +                ('f32.demote/f64', 'b6', False), +                ('f64.convert_s/i32', 'b7', False), +                ('f64.convert_u/i32', 'b8', False), +                ('f64.convert_s/i64', 'b9', False), +                ('f64.convert_u/i64', 'ba', False), +                ('f64.promote/f32', 'bb', False), +                ('i32.reinterpret/f32', 'bc', False), +                ('i64.reinterpret/f64', 'bd', False), +                ('f32.reinterpret/i32', 'be', False), +                ('f64.reinterpret/i64', 'bf', False)] + +    type_ops = [('i32', '7f'), ('i64', '7e'), ('f32', '7d'), +                ('f64', '7c'), ('anyfunc', '7b'), ('func', '60'), +                ('empty_block_type', '40')] +    type_ops_dict = dict(type_ops) +    type_ops_dict_rev = {v: k for k, v in type_ops_dict.items()} + +    control_flow_ops = [('unreachable', '00'), ('nop', '01'), +                        ('block', '02'), ('loop', '03'), +                        ('if', '04'), ('else', '05'), +                        ('end', '0b'), ('br', '0c'), +                        ('br_if', '0d'), ('br_table', '0e'), +                        ('return', '0f')] +    control_flow_ops_dict = dict(control_flow_ops) +    control_flow_ops_dict_rev = {v: k for k, v in control_flow_ops_dict.items()} + +    call_ops = [('call', '10'), ('call_indirect', '11')] +    call_ops_dict = dict(call_ops) +    call_ops_dict_rev = {v: k for k, v in call_ops_dict.items()} + +    param_ops = [('drop', '1a'), ('select', '1b')] +    param_ops_dict = dict(param_ops) +    param_ops_dict_rev = {v: k for k, v in param_ops_dict.items()} + +    var_access = [('get_local', '20'), ('set_local', '21'), +                    ('tee_local', '22'), ('get_global', '23'), +                    ('set_global', '24')] +    var_access_dict = dict(var_access) +    var_access_dict_rev = {v: k for k, v in var_access_dict.items()} + +    mem_ops = [('i32.load', '28'), ('i64.load', '29'), +                ('f32.load', '2a'), ('f64.load', '2b'), +                ('i32.load8_s', '2c'), ('i32.load8_u', '2d'), +                ('i32.load16_s', '2e'),  ('i32.load16_u', '2f'), +                ('i64.load8_s', '30'), ('i64.load8_u', '31'), +                ('i64.load16_s', '32'), ('i64.load16_u', '33'), +                ('i64.load32_s', '34'), ('i64.load32_u', '35'), +                ('i32.store', '36'), ('i64.store', '37'), +                ('f32.store', '38'), ('f64.store', '39'), +                ('i32.store8', '3a'), ('i32.store16', '3b'), +                ('i64.store8', '3c'), ('i64.store16', '3d'), +                ('i64.store32', '3e'), ('current_memory', '3f'), +                ('grow_memory', '40')] +    mem_ops_dict = dict(mem_ops) +    mem_ops_dict_rev = {v: k for k, v in mem_ops_dict.items()} + +    consts = [('i32.const', '41'), ('i64.const', '42'), +              ('f32.const', '43'), ('f64', '44')] +    consts_dict = dict(consts) +    consts_dict_rev = {v: k for k, v in consts_dict.items()} + +    comp_ops = [('i32.eqz', '45'), ('i32.eq', '46'), ('i32.ne', '47'), +                ('i32.lt_s', '48'), ('i32.lt_u', '49'), +                ('i32.gt_s', '4a'), ('i32.gt_u', '4b'), +                ('i32.le_s', '4c'), ('i32.le_u', '4d'), +                ('i32.ge_s', '4e'), ('i32.ge_u', '4f'), +                ('i64.eqz', '50'), ('i64.eq', '51'), +                ('i64.ne', '52'), ('i64.lt_s', '53'), +                ('i64.lt_u', '54'), ('i64.gt_s', '55'), +                ('i64.gt_u', '56'), ('i64.le_s', '57'), +                ('i64.le_u', '58'), ('i64.ge_s', '59'), +                ('i64.ge_u', '5a'), ('f32.eq', '5b'), +                ('f32.ne', '5c'), ('f32.lt', '5d'), +                ('f32.gt', '5e'), ('f32.le', '5f'), +                ('f32.ge', '60'), ('f64.eq', '61'), +                ('f64.ne', '62'), ('f64.lt', '63'), +                ('f64.gt', '64'), ('f64.le', '65'), +                ('f64.ge', '66')] +    comp_ops_dict = dict(comp_ops) +    comp_ops_dict_rev = {v: k for k, v in comp_ops_dict.items()} + +    num_ops = [('i32.clz', '67'), ('i32.ctz', '68'), +               ('i32.popcnt', '69'), ('i32.add', '6a'), +               ('i32.sub', '6b'), ('i32.mul', '6c'), +               ('i32.div_s', '6d'), ('i32.div_u', '6e'), +               ('i32.rem_s', '6e'), ('i32.rem_u', '70'), +               ('i32.and', '71'), ('i32.or', '72'), +               ('i32.xor', '73'), ('i32.shl', '74'), +               ('i32.shr_s', '75'), ('i32.shr_u', '76'), +               ('i32.rotl', '77'), ('i32.rotr', '78'), +               ('i64.clz', '79'), ('i64.ctz', '7a'), +               ('i64.popcnt', '7b'), ('i64.add', '7c'), +               ('i64.sub', '7d'), ('i64.mul', '7e'), +               ('i64.div_s', '7f'), ('i64.div_u', '80'), +               ('i64.rem_s', '81'), ('i64.rem_u', '82'), +               ('i64.and', '83'), ('i64.or', '84'), +               ('i64.xor', '85'), ('i64.shl', '86'), +               ('i64.shr_s', '87'), ('i64.shr_u', '88'), +               ('i64.rotl', '89'), ('i63.rotr', '8a'), +               ('f32.abs', '8b'), ('f32.neg', '8c'), +               ('f32.ceil', '8d'),  ('f32.floor', '8e'), +               ('f32.trunc', '8f'), ('f32.nearest', '90'), +               ('f32.sqrt', '91'), ('f32.add', '92'), +               ('f32.sub', '93'), ('f32.mul', '94'), +               ('f32.div', '95'), ('f32.min', '96'), +               ('f32.max', '97'), ('f32.copysign', '98'), +               ('f64.abs', '99'), ('f64.neg', '9a'), +               ('f64.ceil', '9b'), ('f64.floor', '9c'), +               ('f64.trunc', '9d'), ('f64.nearest', '9e'), +               ('f64.sqrt', '9f'), ('f64.add', 'a0'), +               ('f64.sub', 'a1'), ('f64.mul', 'a2'), +               ('f64.div', 'a3'), ('f64.min', 'a4'), +               ('f64.max', 'a5'), ('f64.copysign', 'a6')] +    num_ops_dict = dict(num_ops) +    num_ops_dict_rev = {v: k for k, v in num_ops_dict.items()} + +    conversion = [('i32.wrap/i64', 'a7'), +                    ('i32.trunc_s/f32', 'a8'), +                    ('i32.trunc_u/f32', 'a9'), +                    ('i32.trunc_s/f64', 'aa'), +                    ('i32.trunc_u/f64', 'ab'), +                    ('i64.extend_s/i32', 'ac'), +                    ('i64.extend_u/i32', 'ad'), +                    ('i64.trunc_s/f32', 'ae'), +                    ('i64.trunc_u/f32', 'af'), +                    ('i64.trunc_s/f64', 'b0'), +                    ('i64.trunc_u/f64', 'b1'), +                    ('f32.convert_s/i32', 'b2'), +                    ('f32.convert_u/i32', 'b3'), +                    ('f32.convert_s/i64', 'b4'), +                    ('f32.convert_u/i64', 'b5'), +                    ('f32.demote/f64', 'b6'), +                    ('f64.convert_s/i32', 'b7'), +                    ('f64.convert_u/i32', 'b8'), +                    ('f64.convert_s/i64', 'b9'), +                    ('f64.convert_u/i64', 'ba'), +                    ('f64.promote/f32', 'bb')] +    conversion_dict = dict(conversion) +    conversion_dict_rev = {v: k for k, v in conversion_dict.items()} + +    reinterpretations = [('i32.reinterpret/f32', 'bc'), +                         ('i64.reinterpret/f64', 'bd'), +                         ('f32.reinterpret/i32', 'be'), +                         ('f64.reinterpret/i64', 'bf')] +    reinterpretations_dict = dict(reinterpretations) +    reinterpretations_dict_rev = {v: k for k, +                                  v in reinterpretations_dict.items()} + +    section_code = [('type', '01'), ('import', '02'), +                    ('function', '03'), ('table', '04'), +                    ('memory', '05'), ('global', '06'), +                    ('export', '07'), ('start', '08'), +                    ('element', '09'), ('code', '0a'), +                    ('data', '0b'), ('custom', '00')] +    section_code_dict = dict(section_code) +    section_code_dict_rev = {v: k for k, v in section_code_dict.items()} diff --git a/bruiser/wasm/TBInit.py b/bruiser/wasm/TBInit.py new file mode 100644 index 0000000..f14dfd1 --- /dev/null +++ b/bruiser/wasm/TBInit.py @@ -0,0 +1,415 @@ +from utils import Colors, init_interpret, ParseFlags +from OpCodes import WASM_OP_Code +from section_structs import Code_Section, Func_Body, WASM_Ins, Resizable_Limits, Memory_Section +from execute import * +import datetime as dti +import os +import sys +import signal + + +# McCabe cyclomatic complexity metric +class Metric(): +    def __init__(self, code_section): +        self.code_section = code_section +        self.metric = [] +        self.soc = [] + +    def mccabe(self): +        soc = 0 +        Edges = 1 +        Nodes = 1 +        for funcs in self.code_section.func_bodies: +            for ins in funcs.code: +                soc += 1 +                #print(repr(ins.opcodeint)) +                if ins.opcodeint == 4 or ins.opcodeint == 5 or ins.opcodeint == 12 \ +                    or ins.opcodeint == 13 or ins.opcodeint == 14: +                    Nodes += 2 +                    Edges += 4 +                elif ins.opcode == 3: +                    Nodes += 2 +                    Edges += 3 +                else: +                    pass + +            self.metric.append(Edges - Nodes + 1) +            self.soc.append(soc) +            soc = 0 +            Edges = 1 +            Nodes = 1 + +    def getMcCabe(self): +        return self.metric + +    def getSOC(self): +        return self.soc + + +# handles the debug option --memdump. dumps the contents of linear memories. +def DumpLinearMems(linear_memories, threshold): +    count = int() +    strrep = [] +    linmem_cnt = int() +    for lin_mem in linear_memories: +        print('-----------------------------------------') +        print(Colors.blue + Colors.BOLD + 'Linear Memory '+ repr(linmem_cnt)+ ' :' + Colors.ENDC) +        for byte in lin_mem: +            if count >= threshold: +                break +            if count%16 == 0: +                for ch in strrep: +                    # @DEVI-line feed messes the pretty format up +                    if ord(ch) != 10: +                        print(Colors.green + ' ' + ch + Colors.ENDC, end = '') +                    else: +                        pass +                print() +                strrep = [] +                print(Colors.cyan + hex(count), ':\t' + Colors.ENDC, end='') +                strrep.append(str(chr(byte))) +                print(Colors.blue + format(byte, '02x') + ' ' + Colors.ENDC, end='') +            else: +                strrep += str(chr(byte)) +                print(Colors.blue + format(byte, '02x') + ' ' + Colors.ENDC, end='') +            count += 1 +        count = 0 +    print() + + +# handles the debug options --idxspc. dumps the index spaces. +def DumpIndexSpaces(machinestate): +    print('-----------------------------------------') +    print(Colors.green + 'Function Index Space: ' + Colors.ENDC) +    for iter in machinestate.Index_Space_Function: +        print(Colors.blue + repr(iter) + Colors.ENDC) + +    print('-----------------------------------------') +    print(Colors.green + 'Globa Index Space: ' + Colors.ENDC) +    for iter in machinestate.Index_Space_Global: +        print(Colors.blue + repr(iter) + Colors.ENDC) + +    print('-----------------------------------------') +    print(Colors.green + 'Linear Memory Index Space: ' + Colors.ENDC) +    for iter in machinestate.Index_Space_Linear: +        print(Colors.blue + repr(iter) + Colors.ENDC) + +    print('-----------------------------------------') +    print(Colors.green + 'Table Index Space: ' + Colors.ENDC) +    for iter in machinestate.Index_Space_Table: +        print(Colors.blue + repr(iter) + Colors.ENDC) +    print('-----------------------------------------') + + +# WIP-the Truebit Machine class +class TBMachine(): +    def __init__(self): +        # bytearray of size PAGE_SIZE +        self.Linear_Memory = [] +        self.Stack_Label = list() +        self.Stack_Label_Height = int() +        self.Stack_Control_Flow = list() +        self.Stack_Call = list() +        self.Stack_Value = list() +        self.Stack_Omni = list() +        self.Vector_Globals = list() +        self.Index_Space_Function = list() +        self.Index_Space_Global = list() +        self.Index_Space_Linear = list() +        self.Index_Space_Table = list() +        self.Index_Space_Locals = list() +        self.Index_Space_Label = list() + + +# handles the initialization of the WASM machine +class TBInit(): +    def __init__(self, module, machinestate): +        self.module = module +        self.machinestate = machinestate + +    # a convenience function that runs the methods of the class. all methods +    # can be called separately manually as well. +    def run(self): +        self.InitFuncIndexSpace() +        self.InitGlobalIndexSpace() +        self.InitLinearMemoryIndexSpace() +        self.InitTableIndexSpace() +        self.InitializeLinearMemory() + +    def InitFuncIndexSpace(self): +        if self.module.import_section is not None: +            for iter in self.module.import_section.import_entry: +                if iter.kind == 0: +                    name = str() +                    for i in iter.field_str: +                        name += str(chr(i)) +                    self.machinestate.Index_Space_Function.append(name) + +        if self.module.function_section is not None: +            for iter in self.module.function_section.type_section_index: +                self.machinestate.Index_Space_Function.append(iter) + +    def InitGlobalIndexSpace(self): +        if self.module.import_section is not None: +            for iter in self.module.import_section.import_entry: +                if iter.kind == 3: +                    name = str() +                    for i in iter.field_str: +                        name += str(chr(i)) +                    self.machinestate.Index_Space_Global.append(name) + +        if self.module.global_section is not None: +            for iter in self.module.global_section.global_variables: +                self.machinestate.Index_Space_Global.append(iter.init_expr) + +    def InitLinearMemoryIndexSpace(self): +        if self.module.import_section is not None: +            for iter in self.module.import_section.import_entry: +                if iter.kind == 2: +                    name = str() +                    for i in iter.field_str: +                        name += str(chr(i)) +                    self.machinestate.Index_Space_Linear.append(name) + +        if self.module.memory_section is not None: +            for iter in self.module.memory_section.memory_types: +                self.machinestate.Index_Space_Linear.append(iter.initial) + +    def InitTableIndexSpace(self): +        if self.module.import_section is not None: +            for iter in self.module.import_section.import_entry: +                if iter.kind == 1: +                    name = str() +                    for i in iter.field_str: +                        name += str(chr(i)) +                    self.machinestate.Index_Space_Table.append(name) + +        if self.module.table_section is not None: +            for iter in self.module.table_section.table_types: +                self.machinestate.Index_Space_Table.append(iter.element_type) + +    def InitializeLinearMemory(self): +        # @DEVI-we could try to pack the data in the linear memory ourselve to +        # decrease the machinestate size +        if self.module.memory_section is None: +            rsz_limits = Resizable_Limits() +            self.module.memory_section = Memory_Section() +            self.module.memory_section.memory_types = [rsz_limits] +            self.module.memory_section.count = 1 +        for iter in self.module.memory_section.memory_types: +            self.machinestate.Linear_Memory.append(bytearray( +                WASM_OP_Code.PAGE_SIZE)) +        if self.module.data_section is not None: +            for iter in self.module.data_section.data_segments: +                count = int() +                for byte in iter.data: +                    self.machinestate.Linear_Memory[iter.index][init_interpret(iter.offset) + count] = byte +                    count += 1 + +    # returns the machinestate +    def getInits(self): +        return(self.machinestate) + + +# WIP-holds the run-rime data structures for a wasm machine +class RTE(): +    def __init__(self): +        Stack_Control_Flow = list() +        Stack_Value = list() +        Vector_Locals = list() +        Current_Position = int() +        Local_Stacks = list() + +    def genFuncLocalStack(func_body): +        pass + + +# palceholder for the class that holds the validation functions +class ModuleValidation(): +    def __init__(self, module): +        self.module = module + +    def TypeSection(self): +        pass + +    def ImportSection(self): +        pass + +    def FunctionSection(self): +        pass + +    def TableSection(self): +        pass + +    def MemorySection(self): +        pass + +    def GlobalSection(self): +        pass + +    def ExportSection(self): +        pass + +    def StartSection(self): +        pass + +    def ElementSection(self): +        pass + +    def CodeSection(self): +        pass + +    def DataSection(self): +        pass + +    def TBCustom(self): +        pass + +    def ValidateAll(self): +        self.TypeSection() +        self.ImportSection() +        self.FunctionSection() +        self.TableSection() +        self.MemorySection() +        self.GlobalSection() +        self.ExportSection() +        self.StartSection() +        self.ElementSection() +        self.CodeSection() +        self.DataSection() +        self.TBCustom() + +        return(True) + + +# a convinience class that handles the initialization of the wasm machine and +# interpretation of the code. +class VM(): +    def __init__(self, modules): +        self.modules = modules +        self.machinestate = TBMachine() +        # @DEVI-FIXME- the first implementation is single-module only +        self.init = TBInit(self.modules[0], self.machinestate) +        self.init.run() +        self.machinestate = self.init.getInits() +        self.start_function = Func_Body() +        self.ins_cache = WASM_Ins() +        self.executewasm = Execute(self.machinestate) +        self.totGas = int() +        self.metric = Metric(modules[0].code_section) +        self.parseflags = None + +    def setFlags(self, parseflags): +        self.parseflags = parseflags + +    def getState(self): +        return(self.machinestate) + +    def initLocalIndexSpace(self, local_count): +        for i in range(0, local_count): +            self.machinestate.Index_Space_Locals.append(0) + +    def getStartFunctionIndex(self): +        if self.modules[0].start_section is None: +            if self.parseflags.entry is None: +                raise Exception(Colors.red + "module does not have a start section. no function index was provided with the --entry option.quitting..." + Colors.ENDC) +            else: +                start_index = int(self.parseflags.entry) +        else: +            print(Colors.green + "found start section: " + Colors.ENDC, end = '') +            start_index = self.modules[0].start_section.function_section_index + +        print(Colors.blue + Colors.BOLD + "running function at index " + repr(start_index) + Colors.ENDC) +        if (start_index > len(self.modules[0].code_section.func_bodies) - 1): +            raise Exception(Colors.red + "invalid function index: the function index does not exist." + Colors.ENDC) +        return(start_index) + +    def getStartFunctionBody(self): +        start_index = self.getStartFunctionIndex() +        if isinstance(start_index, int): +            self.start_function = self.modules[0].code_section.func_bodies[start_index] +        elif isinstance(start_index, str): +            # we have to import the function from another module/library. we +            # assume sys calls are not present.:w +            pass +        else: +            raise Exception(Colors.red + "invalid entry for start function index" + Colors.ENDC) + +    def execute(self): +        print(Colors.blue + Colors.BOLD + 'running module with code: ' + Colors.ENDC) +        for ins in self.start_function.code: +            print(Colors.purple + repr(ins.opcode) + ' ' + repr(ins.operands) + Colors.ENDC) +        for ins in self.start_function.code: +            self.executewasm.getInstruction(ins.opcodeint, ins.operands) +            self.executewasm.callExecuteMethod() +            self.getState() + +    # pre-execution hook +    def startHook(self): +        if self.parseflags.metric: +            for mem in self.modules[0].memory_section.memory_types: +                self.executewasm.chargeGasMem(mem.initial) + +            self.metric.mccabe() +            print(Colors.red + "mccabe: " + repr(self.metric.getMcCabe()) + Colors.ENDC) +            print(Colors.red + "soc: " + repr(self.metric.getSOC()) + Colors.ENDC) + +    # post-execution hook +    def endHook(self): +        if self.parseflags.gas: +            self.totGas = self.executewasm.getOPGas() +            print(Colors.red + "total gas cost: " + repr(self.totGas) + Colors.ENDC) +        if self.machinestate.Stack_Omni: +            print(Colors.green + "stack top: " + repr(self.machinestate.Stack_Omni.pop()) + Colors.ENDC) + +    # a convinience method +    def run(self): +        self.startHook() +        self.getStartFunctionBody() +        self.initLocalIndexSpace(self.start_function.local_count) +        self.execute() +        self.endHook() + + +# a wrapper class for VM. it timeouts instructions that take too long to +# execute. +class Judicator(): +    def __int__(self, op_time_table, module): +        self.op_time_table = op_time_table +        self.vm = VM(modules) +        self.vm.getStartFunctionBody() + +    def overseer(): +        # @DEVI- forking introduces a new source of non-determinism +        pid = os.fork() +        # child process +        if pid == 0: +            sys.stdout = open('./jstdout', 'w') +            sys.stderr = open('./jstderr', 'w') +            self.vm.execute() +            sys.exit() +        # parent process +        if pid > 0: +            cpid, status = os.waitpid(pid, 0) +            if status == 0: +                print('overseer child exited successfully.') +            else: +                print('overseer child exited with non-zero.') +        # pid < 0 +        else: +            raise Exception(Colors.red + 'could not fork judicator overseer.' + Colors.ENDC) + +    def setup(self): +        signal.signal(signal.SIGALRM, self.to_sighandler) + +    def set_alarm(t): +        signal.alaram(t) + +    def to_sighandler(signum, frame): +        print(Colors.red + "execution time out..." + Colors.ENDC) +        raise Exception(Colors.red + "execution time out" + Colors.ENDC) + +    def run(self): +        self.setup() +        self.set_alaram(10) +        self.overseer() diff --git a/bruiser/wasm/dwasm.py b/bruiser/wasm/dwasm.py new file mode 100755 index 0000000..bb930f9 --- /dev/null +++ b/bruiser/wasm/dwasm.py @@ -0,0 +1,1032 @@ +#!/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) + +    # 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() diff --git a/bruiser/wasm/execute.py b/bruiser/wasm/execute.py new file mode 100644 index 0000000..af8455f --- /dev/null +++ b/bruiser/wasm/execute.py @@ -0,0 +1,1056 @@ +from OpCodes import * +from utils import Colors, ror, rol +import numpy as np +import math + + +class Label(): +    def __init__(self, arity, name): +        self.arity = arity +        self.name = name + + +class Frame(): +    def __init__(self, arity, local_indices, self_ref): +        self.arity = arity +        self.local_indices = local_indices +        self.self_ref = self_ref + + +# takes the machinestate, opcode and operand to run. updates the machinestate +class Execute(): # pragma: no cover +    def __init__(self, machinestate): +        self.machinestate = machinestate +        self.opcodeint = '' +        self.immediates = [] +        self.op_gas = int() +        self.stack_top = [] + +    def getOPGas(self): +        return self.op_gas + +    def chargeGasMem(self, mem_size_page): +        factor = 64 +        self.op_gas += 64 * mem_size_page + +    def chargeGas(self, opcodeint): +        if opcodeint != 64: +            self.op_gas += 1 +        else: +            chargeGasMem() +            pass + +    def getInstruction(self, opcodeint, immediates): +        self.opcodeint = opcodeint +        dummy = [] +        #FIXME-why is it being cast to int? +        for i in immediates: +            dummy.append(int(i)) +        self.immediates = dummy + +    def callExecuteMethod(self): +        runmethod = self.instructionUnwinder(self.opcodeint, self.immediates, self.machinestate) +        #print (repr(hex(self.opcodeint)) + ' ' + repr(self.immediates)) +        try: +            runmethod(self.opcodeint, self.immediates) +        except IndexError: +            # trap +            print(Colors.red + 'bad stack access.' + Colors.ENDC) +            val2 = self.machinestate.Stack_Omni.pop() + + +    def instructionUnwinder(self, opcodeint, immediates, machinestate): +        self.chargeGas(opcodeint) + +        if opcodeint == 0: +            return(self.run_unreachable) +        elif opcodeint == 1: +            return(self.run_nop) +        elif opcodeint == 2: +            return(self.run_block) +        elif opcodeint == 3: +            return(self.run_loop) +        elif opcodeint == 4: +            return(self.run_if) +        elif opcodeint == 5: +            return(self.run_else) +        elif opcodeint == 11: +            return(self.run_end) +        elif opcodeint == 12: +            return(self.run_br) +        elif opcodeint == 13: +            return(self.run_br_if) +        elif opcodeint == 14: +            return(self.run_br_table) +        elif opcodeint == 15: +            return(self.run_return) +        elif opcodeint == 16: +            return(self.run_call) +        elif opcodeint == 17: +            return(self.run_call_indirect) +        elif opcodeint == 26: +            return(self.run_drop) +        elif opcodeint == 27: +            return(self.run_select) +        elif opcodeint == 32: +            return(self.run_getlocal) +        elif opcodeint == 33: +            return(self.run_setlocal) +        elif opcodeint == 34: +            return(self.run_teelocal) +        elif opcodeint == 35: +            return(self.run_getglobal) +        elif opcodeint == 36: +            return(self.run_setglobal) +        elif opcodeint >= 40 and opcodeint <= 53: +            return(self.run_load) +        elif opcodeint >= 54 and opcodeint <= 62: +            return(self.run_store) +        elif opcodeint == 63: +            return(self.run_current_memory) +        elif opcodeint == 64: +            self.chargeGasMem(immediates[0]) +            return(self.run_grow_memory) +        elif opcodeint >= 65 and opcodeint <= 68: +            return(self.run_const) +        elif opcodeint == 69 or opcodeint == 80: +            return(self.run_eqz) +        elif opcodeint == 70 or opcodeint == 81 or opcodeint == 91 or opcodeint == 97: +            return(self.run_eq) +        elif opcodeint == 71 or opcodeint == 82 or opcodeint == 92 or opcodeint == 98: +            return(self.run_ne) +        elif opcodeint == 72 or opcodeint == 83: +            return(self.run_lt_s) +        elif opcodeint == 73 or opcodeint == 84: +            return(self.run_lt_u) +        elif opcodeint == 74 or opcodeint == 85: +            return(self.run_gt_s) +        elif opcodeint == 75 or opcodeint == 86: +            return(self.run_gt_u) +        elif opcodeint == 76 or opcodeint == 87: +            return(self.run_le_s) +        elif opcodeint == 77 or opcodeint == 88: +            return(self.run_le_u) +        elif opcodeint == 78 or opcodeint == 89: +            return(self.run_ge_s) +        elif opcodeint == 79 or opcodeint == 90: +            return(self.run_ge_u) +        elif opcodeint == 93 or opcodeint == 99: +            return(self.run_lt) +        elif opcodeint == 94 or opcodeint == 100: +            return(self.run_gt) +        elif opcodeint == 95 or opcodeint == 101: +            return(self.run_le) +        elif opcodeint == 96 or opcodeint == 102: +            return(self.run_ge) +        elif opcodeint == 103 or opcodeint == 121: +            return(self.run_clz) +        elif opcodeint == 104 or opcodeint == 122: +            return(self.run_ctz) +        elif opcodeint == 105 or opcodeint == 123: +            return(self.run_popcnt) +        elif opcodeint == 106 or opcodeint == 124 or opcodeint == 146 or opcodeint == 160: +            return(self.run_add) +        elif opcodeint == 107 or opcodeint == 125 or opcodeint == 147 or opcodeint == 161: +            return(self.run_sub) +        elif opcodeint == 108 or opcodeint == 126 or opcodeint == 148 or opcodeint == 162: +            return(self.run_mul) +        elif opcodeint == 109 or opcodeint == 127: +            return(self.run_div_s) +        elif opcodeint == 110 or opcodeint == 128: +            return(self.run_div_u) +        elif opcodeint == 111 or opcodeint == 129: +            return(self.run_rem_s) +        elif opcodeint == 112 or opcodeint == 130: +            return(self.run_rem_u) +        elif opcodeint == 113 or opcodeint == 131: +            return(self.run_and) +        elif opcodeint == 114 or opcodeint == 132: +            return(self.run_or) +        elif opcodeint == 115 or opcodeint == 133: +            return(self.run_xor) +        elif opcodeint == 116 or opcodeint == 134: +            return(self.run_shl) +        elif opcodeint == 117 or opcodeint == 135: +            return(self.run_shr_s) +        elif opcodeint == 118 or opcodeint == 136: +            return(self.run_shr_u) +        elif opcodeint == 119 or opcodeint == 137: +            return(self.run_rotl) +        elif opcodeint == 120 or opcodeint == 138: +            return(self.run_rotr) +        elif opcodeint == 139 or opcodeint == 153: +            return(self.run_abs) +        elif opcodeint == 140 or opcodeint == 154: +            return(self.run_neg) +        elif opcodeint == 141 or opcodeint == 155: +            return(self.run_ceil) +        elif opcodeint == 142 or opcodeint == 156: +            return(self.run_floor) +        elif opcodeint == 143 or opcodeint == 157: +            return(self.run_trunc) +        elif opcodeint == 144 or opcodeint == 158: +            return(self.run_nearest) +        elif opcodeint == 145 or opcodeint == 159: +            return(self.run_sqrt) +        elif opcodeint == 149 or opcodeint == 163: +            return(self.run_div) +        elif opcodeint == 150 or opcodeint == 164: +            return(self.run_min) +        elif opcodeint == 151 or opcodeint == 165: +            return(self.run_max) +        elif opcodeint == 152 or opcodeint == 166: +            return(self.run_copysign) +        elif opcodeint == 167: +            return(self.run_i32wrapi64) +        elif opcodeint == 168: +            return(self.run_i32trunc_sf32) +        elif opcodeint == 169: +            return(self.run_i32trunc_uf32) +        elif opcodeint == 170: +            return(self.run_i32trunc_sf64) +        elif opcodeint == 171: +            return(self.run_i32trunc_uf64) +        elif opcodeint == 172: +            return(self.run_i64extend_si32) +        elif opcodeint == 173: +            return(self.run_i64extend_ui3o) +        elif opcodeint == 174: +            return(self.run_i64trunc_sf32) +        elif opcodeint == 175: +            return(self.run_i64trunc_uf32) +        elif opcodeint == 176: +            return(self.run_i64trunc_sf64) +        elif opcodeint == 177: +            return(self.run_i64trunc_uf64) +        elif opcodeint == 178: +            return(self.run_f32convert_si32) +        elif opcodeint == 179: +            return(self.run_f32convert_ui32) +        elif opcodeint == 180: +            return(self.run_f32convert_si64) +        elif opcodeint == 181: +            return(self.run_f32convert_ui64) +        elif opcodeint == 182: +            return(self.run_f32demotef64) +        elif opcodeint == 183: +            return(self.run_f64convert_si32) +        elif opcodeint == 184: +            return(self.run_f64convert_ui32) +        elif opcodeint == 185: +            return(self.run_f64convert_si64) +        elif opcodeint == 186: +            return(self.run_f64convert_ui64) +        elif opcodeint == 187: +            return(self.run_f64promotef32) +        elif opcodeint == 188: +            return(self.run_i32reinterpretf32) +        elif opcodeint == 189: +            return(self.run_i64reinterpretf64) +        elif opcodeint == 190: +            return(self.run_f32reinterpreti32) +        elif opcodeint == 191: +            return(self.run_f64reinterpreti64) +        else: +            raise Exception(Colors.red + 'unknown opcode' + Colors.ENDC) + +    def run_unreachable(self, opcodeint, immediates): +        # trap +        raise Exception(Colors.red + "trapped." + Colors.ENDC) + +    def run_nop(self, opcodeint, immediates): +        # literally do nothing +        pass + +    def run_block(self, opcodeint, immediates): +        self.machinestate.Stack_Label.append(self.machinestate.Stack_Label_Height) +        self.machinestate.Stack_Label_Height += 1 + +    def run_loop(self, opcodeint, immediates): +        # assertion +        if not self.machinestate.Stack_Omni: +            print(Colors.red + "entered a loop. stack is empty." + Colors.ENDC) +            # exit 1 +        self.machinestate.Stack_Label.append(self.machinestate.Stack_Label_Height) +        self.machinestate.Stack_Label_Height += 1 +        val = self.machinestate.Stack_Omni.pop() +        if val != 0: +            pass +        else: +            pass + +    def run_if(self, opcodeint, immediates): +        pass + +    def run_else(self, opcodeint, immediates): +        pass + +    def run_end(self, opcodeint, immediates): +        #self.machinestate.Stack_Label.pop() +        pass + +    def run_br(self, opcodeint, immediates): +        if self.machinestate.Stack_Label_Height >= immediates[0] + 1: +            print(Colors.red + "label stack does not have enough labels." + Colors.ENDC) +            # exit 1 +        if len(self.machinestate.Stack_Omni) < 1: +            print(Colors.red + "the value stack does not have enough values." + Colors.ENDC) +            # exit 1 +        val = self.machinestate.Stack_Omni.pop() +        label = self.machinestate.Stack_Label.pop() + +    def run_br_if(self, opcodeint, immediates): +        val = self.machinestate.Stack_Omni.pop() +        if val: +            pass +        else: +            self.run_br(dummy, immediates[0]) + +    def run_br_table(self, opcodeint, immediates): +        pass + +    def run_return(self, opcodeint, immediates): +        pass + +    def run_call(self, opcodeint, immediates): +        pass + +    def run_call_indirect(self, opcodeint, immediates): +        pass + +    def run_drop(self, opcodeint, immediates): +        self.machinestate.Stack_Omni.pop() + +    def run_select(self, opcodeint, immediates): +        pass + +    def run_getlocal(self, opcodeint, immediates): +        local = self.machinestate.Index_Space_Locals[int(immediates[0])] +        self.machinestate.Stack_Omni.append(local) + +    def run_setlocal(self, opcodeint, immediates): +        self.machinestate.Index_Space_Locals[int(immediates[0])] = self.machinestate.Stack_Omni.pop() + +    def run_teelocal(self, dummy, immediates): +        # @DEVI-we dont pop and push +        self.machinestate.Index_Space_Locals[int(immediates[0])] = self.machinestate.Stack_Omni[-1] + +    def run_getglobal(self, opcodeint, immediates): +        val = self.machinestate.Index_Space_Global[immediates[0]] +        self.machinestate.Stack_Omni.append(val) + +    def run_setglobal(self, opcodeint, immediates): +        val = self.machinestate.Stack_Omni.pop() +        self.machinestate.Index_Space_Global = val + +    # currently only one linear memory is allowed so thats the default. +    def run_load(self, opcodeint, immediates): +        if opcodeint == 40: +            bytes = self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates) + 4] +            self.machinestate.Stack_Omni.append(np.int32(bytes)) +        elif opcodeint == 41: +            bytes = self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates) + 8] +            self.machinestate.Stack_Omni.append(np.int64(bytes)) +        elif opcodeint == 42: +            bytes = self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates) + 4] +            self.machinestate.Stack_Omni.append(np.float32(bytes)) +        elif opcodeint == 43: +            bytes = self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates) + 8] +            self.machinestate.Stack_Omni.append(np.float64(bytes)) +        elif opcodeint == 44: +            temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1])]) +            temp2 = (temp & 0x0000007f) | ((temp & 0x80) << 24) +            self.machinestate.append(np.int32(tmep2)) +        elif opcodeint == 45: +            temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1])]) +            temp2 = temp & 0x000000ff +            self.machinestate.append(np.uint32(tmep2)) +        elif opcodeint == 46: +            temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 2)]) +            temp2 = (temp & 0x00007fff) | ((temp & 0x8000) << 16) +            self.machinestate.append(np.int32(tmep2)) +        elif opcodeint == 47: +            temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 2)]) +            temp2 = temp & 0x0000ffff +            self.machinestate.append(np.uint32(tmep2)) +        elif opcodeint == 48: +            temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1])]) +            temp2 = (temp & 0x000000000000007f) | ((temp & 0x80) << 56) +            self.machinestate.append(np.int64(tmep2)) +        elif opcodeint == 49: +            temp = np.uint8(self.machinestate.Linear_Memory[0][int(immediates[1])]) +            self.machinestate.append(np.uint64(tmep)) +        elif opcodeint == 50: +            temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 2)]) +            temp2 = (temp & 0x0000000000007fff) | ((temp & 0x8000) << 48) +            self.machinestate.append(np.int64(tmep2)) +        elif opcodeint == 51: +            temp = np.uint8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 2)]) +            self.machinestate.append(np.uint64(tmep)) +        elif opcodeint == 52: +            temp = np.int8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 4)]) +            temp2 = (temp & 0x000000007fffffff) | ((temp & 0x80000000) << 32) +            self.machinestate.append(np.int64(tmep2)) +        elif opcodeint == 53: +            temp = np.uint8(self.machinestate.Linear_Memory[0][int(immediates[1]):int(immediates[1] + 4)]) +            self.machinestate.append(np.uint64(tmep)) +        else: +            raise Exception(Colors.red + 'invalid load instruction.' + Colors.ENDC) + +    # currently only one linear memory is allowed so thats the default. +    def run_store(self, opcodeint, immediates): +        if opcodeint == 54: +            val = self.machinestate.Stack_Omni.pop() +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 0] = val & 0x000000ff +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 1] = val & 0x0000ff00 >> 8 +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 2] = val & 0x00ff0000 >> 16 +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 3] = val & 0xff000000 >> 24 +        elif opcodeint == 55: +            val = self.machinestate.Stack_Omni.pop() +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 0] = val & 0x00000000000000ff +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 1] = val & 0x000000000000ff00 >> 8 +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 2] = val & 0x0000000000ff0000 >> 16 +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 3] = val & 0x00000000ff000000 >> 24 +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 4] = val & 0x000000ff00000000 >> 32 +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 5] = val & 0x0000ff0000000000 >> 40 +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 6] = val & 0x00ff000000000000 >> 48 +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 7] = val & 0xff00000000000000 >> 56 +        # @DEVI-FIXME-needs reinterpret cast +        elif opcodeint == 56: +            pass +        # @DEVI-FIXME-needs reinterpret cast +        elif opcodeint == 57: +            pass +        elif opcodeint == 58: +            val = self.machinestate.Stack_Omni.pop() +            self.machinestate.Linear_Memory[0][int(immediates[1])] = np.in8(val & 0x000000ff) +        elif opcodeint == 59: +            val = self.machinestate.Stack_Omni.pop() +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 0] = np.in8(val & 0x000000ff) +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 1] = np.in8(val & 0x0000ff00 >> 8) +        elif opcodeint == 60: +            val = self.machinestate.Stack_Omni.pop() +            self.machinestate.Linear_Memory[0][int(immediates[1])] = np.in8(val & 0x00000000000000ff) +        elif opcodeint == 61: +            val = self.machinestate.Stack_Omni.pop() +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 0] = np.in8(val & 0x00000000000000ff) +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 1] = np.in8(val & 0x000000000000ff00 >> 8) +        elif opcodeint == 62: +            val = self.machinestate.Stack_Omni.pop() +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 0] = np.in8(val & 0x00000000000000ff) +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 1] = np.in8(val & 0x000000000000ff00 >> 8) +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 2] = np.in8(val & 0x0000000000ff0000 >> 16) +            self.machinestate.Linear_Memory[0][int(immediates[1]) + 3] = np.in8(val & 0x00000000ff000000 >> 24) +        else: +            raise Exception(Colors.red + 'invalid store instruction' + Colors.ENDC) + +    def run_current_memory(self, opcodeint, immediates): +        pass + +    def run_grow_memory(self, opcodeint, immediates): +        pass + +    def run_const(self, opcodeint, immediates): +        if opcodeint == 65: +            self.machinestate.Stack_Omni.append(immediates[0]) +        elif opcodeint == 66: +            self.machinestate.Stack_Omni.append(immediates[0]) +        elif opcodeint == 67: +            self.machinestate.Stack_Omni.append(immediates[0]) +        elif opcodeint == 68: +            self.machinestate.Stack_Omni.append(immediates[0]) +        else: +            raise Exception(Colors.red + 'invalid const instruction' + Colors.ENDC) + +    def run_eqz(self, opcodeint, immediates): +        if opcodeint == 69 or opcodeint == 80: +            val = self.machinestate.Stack_Omni.pop() +            if val == 0: +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid eqz instruction' + Colors.ENDC) + +    def run_eq(self, opcodeint, immediates): +        if opcodeint == 70 or opcodeint == 81 or opcodeint == 91 or opcodeint == 97: +            val2 = self.machinestate.Stack_Omni.pop() +            val1 = self.machinestate.Stack_Omni.pop() +            if val1 == val2: +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid eq instruction' + Colors.ENDC) + +    def run_ne(self, opcodeint, immediates): +        if opcodeint == 71 or opcodeint == 82 or opcodeint == 92 or opcodeint == 98: +            val2 = self.machinestate.Stack_Omni.pop() +            val1 = self.machinestate.Stack_Omni.pop() +            if val1 != val2: +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid ne instruction' + Colors.ENDC) + +    def run_lt_s(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 72: +            if np.int32(val1) < np.int32(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 83: +            if np.int64(val1) < np.int64(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid lt_s instruction' + Colors.ENDC) + +    def run_lt_u(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 73: +            if np.uint32(val1) < np.uint32(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 84: +            if np.uint64(val1) < np.uint64(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid lt_u instruction' + Colors.ENDC) + +    def run_gt_s(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 74: +            if np.int32(val1) > np.int32(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 85: +            if np.int64(val1) > np.int64(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid gt_s instruction' + Colors.ENDC) + +    def run_gt_u(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 75: +            if np.uint32(val1) > np.uint32(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 86: +            if np.uint64(val1) > np.uint64(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid gt_u instruction' + Colors.ENDC) + +    def run_le_s(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 76: +            if np.int32(val1) <= np.int32(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 87: +            if np.int64(val1) <= np.int64(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid le_s instruction' + Colors.ENDC) + +    def run_le_u(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 77: +            if np.uint32(val1) <= np.uint32(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 88: +            if np.uint64(val1) <= np.uint64(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid le_u instruction' + Colors.ENDC) + +    def run_ge_s(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 78: +            if np.int32(val1) >= np.int32(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 89: +            if np.int64(val1) >= np.int64(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid ge_s instruction' + Colors.ENDC) + +    def run_ge_u(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 79: +            if np.uint32(val1) >= np.uint32(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 90: +            if np.uint64(val1) >= np.uint64(val2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid ge_u instruction' + Colors.ENDC) + +    def run_lt(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 93: +            if np.float32(v1) < np.float32(v2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 99: +            if np.float64(v1) < np.float64(v2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid lt instruction' + Colors.ENDC) + +    def run_gt(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 94: +            if np.float32(v1) > np.float32(v2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 100: +            if np.float64(v1) > np.float64(v2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid gt instruction' + Colors.ENDC) + +    def run_le(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 95: +            if np.float32(v1) <= np.float32(v2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 101: +            if np.float64(v1) <= np.float64(v2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid le instruction' + Colors.ENDC) + +    def run_ge(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 96: +            if np.float32(v1) >= np.float32(v2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        elif opcodeint == 102: +            if np.float64(v1) >= np.float64(v2): +                self.machinestate.Stack_Omni.append(1) +            else: +                self.machinestate.Stack_Omni.append(0) +        else: +            raise Exception(Colors.red + 'invalid ge instruction' + Colors.ENDC) + +    def run_clz(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 103: +            self.machinestate.Stack_Omni.append(clz(val, 'uint32')) +        elif opcodeint == 121: +            self.machinestate.Stack_Omni.append(clz(val, 'uint64')) +        else: +            raise Exception(Colors.red + 'invalid clz instruction' + Colors.ENDC) + +    def run_ctz(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 104: +            self.machinestate.Stack_Omni.append(ctz(val, 'uint32')) +        elif opcodeint == 122: +            self.machinestate.Stack_Omni.append(ctz(val, 'uint64')) +        else: +            raise Exception(Colors.red + 'invalid ctz instruction' + Colors.ENDC) + +    def run_popcnt(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 105: +            self.machinestate.Stack_Omni.append(pop_cnt(val, 'uint32')) +        elif opcodeint == 123: +            self.machinestate.Stack_Omni.append(pop_cnt(val, 'uint64')) +        else: +            raise Exception(Colors.red + 'invalid popcnt instruction' + Colors.ENDC) + +    def run_add(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 106: +            self.machinestate.Stack_Omni.append(np.uint32(val1 + val2)) +        elif opcodeint == 124: +            self.machinestate.Stack_Omni.append(np.uint64(val1 + val2)) +        elif opcodeint == 146: +            self.machinestate.Stack_Omni.append(np.float32(val1 + val2)) +        elif opcodeint == 160: +            self.machinestate.Stack_Omni.append(np.float64(val1 + val2)) +        else: +            raise Exception(Colors.red + 'invalid add instruction' + Colors.ENDC) + +    def run_sub(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 107: +            self.machinestate.Stack_Omni.append(np.uint32(val1 - val2)) +        elif opcodeint == 125: +            self.machinestate.Stack_Omni.append(np.uint64(val1 - val2)) +        elif opcodeint == 147: +            self.machinestate.Stack_Omni.append(np.float32(val1 - val2)) +        elif opcodeint == 161: +            self.machinestate.Stack_Omni.append(np.float64(val1 - val2)) +        else: +            raise Exception(Colors.red + 'invalid sub instruction' + Colors.ENDC) + +    def run_mul(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 108: +            self.machinestate.Stack_Omni.append(np.uint32(val1 * val2)) +        elif opcodeint == 126: +            self.machinestate.Stack_Omni.append(np.uint64(val1 * val2)) +        elif opcodeint == 148: +            self.machinestate.Stack_Omni.append(np.float32(val1 * val2)) +        elif opcodeint == 162: +            self.machinestate.Stack_Omni.append(np.float64(val1 * val2)) +        else: +            raise Exception(Colors.red + 'invalid mul instruction' + Colors.ENDC) + +    def run_div_s(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 109: +            self.machinestate.Stack_Omni.append(np.int32(np.int32(val1) / np.int32(val2))) +        elif opcodeint == 127: +            self.machinestate.Stack_Omni.append(np.int64(np.int64(val1) / np.int64(val2))) +        else: +            raise Exception(Colors.red + 'invalid div_s instruction' + Colors.ENDC) + +    def run_div_u(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 110: +            self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) / np.uint32(val2))) +        elif opcodeint == 128: +            self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) / np.uint64(val2))) +        else: +            raise Exception(Colors.red + 'invalid div_u instruction' + Colors.ENDC) + +    def run_rem_s(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 111: +            self.machinestate.Stack_Omni.append(np.int32(np.int32(val1) % np.int32(val2))) +        elif opcodeint == 129: +            self.machinestate.Stack_Omni.append(np.int64(np.int64(val1) % np.int64(val2))) +        else: +            raise Exception(Colors.red + 'invalid rem_s instruction' + Colors.ENDC) + +    def run_rem_u(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 112: +            self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) % np.uint32(val2))) +        elif opcodeint == 130: +            self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) % np.uint64(val2))) +        else: +            raise Exception(Colors.red + 'invalid rem_u instruction' + Colors.ENDC) + +    def run_and(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 113: +            self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) & np.uint32(val2))) +        elif opcodeint == 131: +            self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) & np.uint64(val2))) +        else: +            raise Exception(Colors.red + 'invalid and instruction' + Colors.ENDC) + +    def run_or(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 114: +            self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) | np.uint32(val2))) +        elif opcodeint == 132: +            self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) | np.uint64(val2))) +        else: +            raise Exception(Colors.red + 'invalid or instruction' + Colors.ENDC) + +    def run_xor(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 115: +            self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) ^ np.uint32(val2))) +        elif opcodeint == 133: +            self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) ^ np.uint64(val2))) +        else: +            raise Exception(Colors.red + 'invalid xor instruction' + Colors.ENDC) + +    def run_shl(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 116: +            self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) << (np.uint32(val2)))) +        elif opcodeint == 134: +            self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) << (np.uint64(val2)))) +        else: +            raise Exception(Colors.red + 'invalid shl instruction' + Colors.ENDC) + +    def run_shr_s(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 117: +            self.machinestate.Stack_Omni.append(np.int32(np.int32(val1) >> (np.int32(val2)))) +        elif opcodeint == 135: +            self.machinestate.Stack_Omni.append(np.int64(np.int64(val1) >> (np.int64(val2)))) +        else: +            raise Exception(Colors.red + 'invalid shr_s instruction' + Colors.ENDC) + +    def run_shr_u(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 118: +            self.machinestate.Stack_Omni.append(np.uint32(np.uint32(val1) >> (np.uint32(val2)))) +        elif opcodeint == 136: +            self.machinestate.Stack_Omni.append(np.uint64(np.uint64(val1) >> (np.uint64(val2)))) +        else: +            raise Exception(Colors.red + 'invalid shr_u instruction' + Colors.ENDC) + +    def run_rotl(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 119: +            self.machinestate.Stack_Omni.append(rol(val1, 32, val2)) +        elif opcodeint == 137: +            self.machinestate.Stack_Omni.append(rol(val1, 64, val2)) +        else: +            raise Exception(Colors.red + 'invalid rotl instruction' + Colors.ENDC) + +    def run_rotr(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 120: +            self.machinestate.Stack_Omni.append(ror(val1, 32, val2)) +        elif opcodeint == 138: +            self.machinestate.Stack_Omni.append(ror(val1, 32, val2)) +        else: +            raise Exception(Colors.red + 'invalid rotl instruction' + Colors.ENDC) + +    def run_abs(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 139 or opcodeint == 153: +            self.machinestate.Stack_Omni.append(abs(val1)) +        else: +            raise Exception(Colors.red + 'invalid abs instruction' + Colors.ENDC) + +    def run_neg(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 140 or opcodeint == 154: +            self.machinestate.Stack_Omni.append(-val1) +        else: +            raise Exception(Colors.red + 'invalid neg instruction' + Colors.ENDC) + +    def run_ceil(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 141 or opcodeint == 155: +            self.machinestate.Stack_Omni.append(math.ceil(val1)) +        else: +            raise Exception(Colors.red + 'invalid ceil instruction' + Colors.ENDC) + +    def run_floor(self, opcodeint, immediates): +        if opcodeint == 142 or opcodeint == 156: +            self.machinestate.Stack_Omni.append(math.floor(val1)) +        else: +            raise Exception(Colors.red + 'invalid floor instruction' + Colors.ENDC) + +    def run_trunc(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 143 or opcodeint == 157: +            self.machinestate.Stack_Omni.append(math.trunc(val1)) +        else: +            raise Exception(Colors.red + 'invalid trunc instruction' + Colors.ENDC) + +    def run_nearest(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 144 or opcodeint == 158: +            self.machinestate.Stack_Omni.append(round(val1)) +        else: +            raise Exception(Colors.red + 'invalid nearest instruction' + Colors.ENDC) + +    def run_sqrt(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 145 or opcodeint == 159: +            self.machinestate.Stack_Omni.append(math.sqrt(val1)) +        else: +            raise Exception(Colors.red + 'invalid sqrt instruction' + Colors.ENDC) + +    def run_div(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 149: +            self.machinestate.Stack_Omni.append(v1 / v2) +        else: +            raise Exception(Colors.red + 'invalid float div instruction' + Colors.ENDC) + +    def run_min(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 150 or opcodeint == 164: +            self.machinestate.Stack_Omni.append(min(val1, val2)) +        else: +            raise Exception(Colors.red + 'invalid min instruction' + Colors.ENDC) + +    def run_max(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 151 or opcodeint == 165: +            self.machinestate.Stack_Omni.append(max(val1, val2)) +        else: +            raise Exception(Colors.red + 'invalid max instruction' + Colors.ENDC) + +    def run_copysign(self, opcodeint, immediates): +        val2 = self.machinestate.Stack_Omni.pop() +        val1 = self.machinestate.Stack_Omni.pop() +        if opcodeint == 152 or opcodeint == 166: +            self.machinestate.Stack_Omni.append(math.copysign(val1, val2)) +        else: +            raise Exception(Colors.red + 'invalid max instruction' + Colors.ENDC) + +    def run_i32wrapi64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.int32(np.float64(val1))) + +    def run_i32trunc_sf32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.int32(np.float32(val1))) + +    def run_i32trunc_uf32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.uint32(np.float32(val1))) + +    def run_i32trunc_sf64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.int32(np.float64(val1))) + +    def run_i32trunc_uf64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.int32(np.float64(val1))) + +    def run_i64extend_si32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float64(np.int32(val1))) + +    def run_i64extend_ui32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float64(np.uint32(val1))) + +    def run_i64trunc_sf32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.int64(np.float32(val1))) + +    def run_i64trunc_uf32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.uint64(np.float32(val1))) + +    def run_i64trunc_sf64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.int64(np.float64(val1))) + +    def run_i64trunc_uf64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.uint64(np.float64(val1))) + +    def run_f32convert_si32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float32(np.uint32(val1))) + +    def run_f32convert_ui32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float32(np.int32(val1))) + +    def run_f32convert_si64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float32(np.int64(val1))) + +    def run_f32convert_ui64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float32(np.uint64(val1))) + +    def run_f32demotef64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float32(np.float64(val1))) + +    def run_f64convert_si32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float64(np.int32(val1))) + +    def run_f64convert_ui32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float64(np.uint32(val1))) + +    def run_f64convert_si64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float64(np.int64(val1))) + +    def run_f64convert_ui64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float64(np.uint64(val1))) + +    def run_f64promotef32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        self.machinestate.Stack_Omni.append(np.float64(np.float32(val1))) + +    def run_i32reinterpretf32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        sel.machinestate.Stack_Omni.append(reinterpretf32toi32(val1)) + +    def run_i64reinterpretf64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        sel.machinestate.Stack_Omni.append(reinterpretf64toi64(val1)) + +    def run_f32reinterpreti32(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        sel.machinestate.Stack_Omni.append(reinterpreti32tof32(val1)) + +    def run_f64reinterpreti64(self, opcodeint, immediates): +        val1 = self.machinestate.Stack_Omni.pop() +        sel.machinestate.Stack_Omni.append(reinterpreti64tof64(val1)) diff --git a/bruiser/wasm/run.sh b/bruiser/wasm/run.sh new file mode 100755 index 0000000..bcccca1 --- /dev/null +++ b/bruiser/wasm/run.sh @@ -0,0 +1,3 @@ +#!/usr/bin/bash + +"./dwasm.py" --wasm ./test/injected.wasm --section code diff --git a/bruiser/wasm/section_structs.py b/bruiser/wasm/section_structs.py new file mode 100644 index 0000000..b254ff9 --- /dev/null +++ b/bruiser/wasm/section_structs.py @@ -0,0 +1,278 @@ +# contains the data classes we use to hold the information of a module +class WASM_SECTION(object): +    def __init__(self): +        self.section_id = int() +        self.string = str() +        self.payload_length = int() +        self.is_custom_section = bool() +        self.name_len = int() +        self.name = str() +        self.payload_data = bytes() + + +class Reloc_Entry_1(): +    def __init__(self): +        self.offset = int() +        self.index = int() + + +class Reloc_Entry_2(): +    def __init__(self): +        self.offset = int() +        self.index = int() +        self.addend = int() + + +class Relocation_Section(): +    def __int__(self): +        self.section_id = int() +        self.name_length = int() +        self.name = str() +        self.count = int() +        self.entries = int() + + +class Func_Type(): +    def __init__(self): +        self.form = int() +        self.param_cnt = int() +        self.param_types = [] +        self.return_cnt = int() +        self.return_type = [] + + +class Global_Type(): +    def __init__(self): +        self.content_type = int() +        self.mutability = int() + + +class Resizable_Limits(): +    def __init__(self): +        self.flags = int() +        self.initial = int() +        self.maximum = int() + + +class Table_Type(): +    def __init__(self): +        self.element_type = int() +        self.limit = Resizable_Limits() + + +class External_Kind(): +    def __init__(self): +        self.Function = 0 +        self.Table = 1 +        self.Memory = 2 +        self.Global = 3 + + +class Memory_Type(): +    def __init__(self): +        self.limits = [Resizable_Limits()] + + +# @DEVI-FIXME- +class Init_Expr(): +    pass + + +class Type_Section(): +    def __init__(self): +        self.count = [] +        self.func_types = [] + + +class Import_Entry(): +    def __init__(self): +        self.module_len = int() +        self.module_str = [] +        self.field_len = int() +        self.field_str = [] +        self.kind = int() +        self.type = int() + + +class Import_Section(): +    def __init__(self): +        self.count = [] +        self.import_entry = [] + + +class Function_Section(): +    def __init__(self): +        self.count = [] +        self.type_section_index = [int()] + + +class Table_Section(): +    def __init__(self): +        self.count = [] +        self.table_types = [] + + +class Memory_Section(): +    def __init__(self): +        self.count = [] +        # Resizable_Limits +        self.memory_types = [] + + +class Global_Variable(): +    def __init__(self): +        self.global_type = Global_Type() +        self.init_expr = [] + + +class Global_Section(): +    def __init__(self): +        self.count = [] +        # Global_Variable +        self.global_variables = [] + + +class Export_Entry(): +    def __init__(self): +        self.field_len = int() +        self.field_str = [] +        self.kind = int() +        self.index = int() + + +class Export_Section(): +    def __init__(self): +        self.count = [] +        # Export_Entry +        self.export_entries = [] + + +class Start_Section(): +    def __init__(self): +        self.function_section_index = [] + + +class Elem_Segment(): +    def __init__(self): +        self.index = int() +        self.offset = [] +        self.num_elem = int() +        self.elems = [] + + +class Element_Section(): +    def __init__(self): +        self.count = [] +        # Elem_Segment +        self.elem_segments = [] + + +class Local_Entry(): +    def __init__(self): +        self.count = int() +        self.type = int() + + +class WASM_Ins(): +    def __init__(self): +        self.opcode = str() +        self.opcodeint = int() +        self.operands = [] + + +class Func_Body(): +    def __init__(self): +        self.body_size = int() +        self.local_count = int() +        # Local_Entry +        self.locals = [] +        # WASM_Ins +        self.code = [] +        self.end = int() + + +class Code_Section(): +    def __init__(self): +        self.count = [] +        # Func_Body +        self.func_bodies = [] + + +class Data_Segment(): +    def __init__(self): +        self.index = int() +        self.offset = [] +        self.size = int() +        self.data = [] + + +class Data_Section(): +    def __init__(self): +        self.count = [] +        # Data_Segment +        self.data_segments = [] + + +class Name_Type(): +    Module = 0 +    Function = 1 +    Local = 2 + + +class Name_Section_Entry(object): +    def __init__(self, name_type, name_payload_len, name_payload_data): +        self.name_type = name_type +        self.name_payload_len = name_payload_len +        self.name_payload_data = name_payload_data + + +class Name_Section(object): +    def __init__(self, name_section_entry): +        self.name_section_entry = [] +        self.name_section_entry = name_section_entry + + +class Module_Name(object): +    def __init__(self, name_len, name_str): +        self.name_len = name_len +        self.name_str = name_str + + +class Naming(object): +    def __init__(self, index, name_len, name_str): +        self.index = index +        self.name_len = name_len +        self.name_str = name_str + + +class Name_Map(object): +    def __init__(self, count, naming): +        self.count = count +        self.naming = [] +        self.naming = naming + + +# the module class +class Module(): +    def __init__(self, type_section, import_section, function_section, +                 table_section, memory_section, global_section, export_section, +                 start_section, element_section, code_section, data_section): +        self.type_section = type_section +        self.import_section = import_section +        self.function_section = function_section +        self.table_section = table_section +        self.memory_section = memory_section +        self.global_section = global_section +        self.export_section = export_section +        self.start_section = start_section +        self.element_section = element_section +        self.code_section = code_section +        self.data_section = data_section + +''' +class RT_INS_CELL(object): +    def __init__(self): +        label : str +        mnemonic : str +        ops : list +''' diff --git a/bruiser/wasm/test/injected.wasm b/bruiser/wasm/test/injected.wasmBinary files differ new file mode 100644 index 0000000..59f492c --- /dev/null +++ b/bruiser/wasm/test/injected.wasm diff --git a/bruiser/wasm/utils.py b/bruiser/wasm/utils.py new file mode 100644 index 0000000..6f93a94 --- /dev/null +++ b/bruiser/wasm/utils.py @@ -0,0 +1,425 @@ +from OpCodes import * +import numpy as np +import struct as stc + +class ParseFlags: +    def __init__(self, wast_path, wasm_path, as_path, disa_path, out_path, dbg, unval, memdump +                 , idxspc, run, metric, gas, entry): +        self.wast_path = wast_path +        self.wasm_path = wasm_path +        self.as_path = as_path +        self.disa_path = disa_path +        self.out_path = out_path +        self.dbg = dbg +        self.unval = unval +        self.memdump = memdump +        self.idxspc = idxspc +        self.run = run +        self.metric = metric +        self.gas = gas +        self.entry = entry + +# pretty print +class Colors: +    purple = '\033[95m' +    blue = '\033[94m' +    green = '\033[92m' +    yellow = '\033[93m' +    red = '\033[91m' +    grey = '\033[1;37m' +    darkgrey = '\033[1;30m' +    cyan = '\033[1;36m' +    ENDC = '\033[0m' +    BOLD = '\033[1m' +    UNDERLINE = '\033[4m' + +def LEB128UnsignedDecode(bytelist): +    result = 0 +    shift = 0 +    for byte in bytelist: +        result |= (byte & 0x7f) << shift +        if (byte & 0x80) == 0: +            break +        shift += 7 +    return(result) + +def LEB128SignedDecode(bytelist): +    result = 0 +    shift = 0 +    for byte in bytelist: +        result |= (byte & 0x7f) << shift +        last_byte = byte +        shift += 7 +        if (byte & 0x80) == 0: +            break + +    if last_byte & 0x40: +        result |= - (1 << shift) + +    return(result) + +def LEB128UnsignedEncode(int_val): +    if int_val < 0: +        raise Exception("value must not be negative") +    elif int_val == 0: +        return bytes([0]) + +    byte_array = bytearray() +    while int_val: +        byte = int_val & 0x7f +        byte_array.append(byte | 0x80) +        int_val >>= 7 + +    byte_array[-1] ^= 0x80 + +    return(byte_array) + + +def LEB128SignedEncode(int_val): +    byte_array = bytearray() +    while True: +        byte = int_val & 0x7f +        byte_array.append(byte | 0x80) +        int_val >>= 7 +        if (int_val == 0 and byte&0x40 == 0) or (int_val == -1 and byte&0x40): +            byte_array[-1] ^= 0x80 +            break + +    return(byte_array) + +# @DEVI-FIXME-MVP-only-we currently inly support consts and get_global +# interprets the init-exprs +def init_interpret(expr): +    offset = 0 +    byte, offset, dummy = Read(expr, offset, 'uint8') +    const = int() + +    if byte == 65: +        # @DEVI-FIXME-the spec says varint32, obviously we are not doing that +        # since it will return neg values which are meningless and break things +        const, offset, dummy = Read(expr, offset, 'varuint32') +    elif byte == 66: +        const, offset, dummy = Read(expr, offset, 'varint64') +    elif byte == 67: +        const, offset, dummy = Read(expr, offset, 'uint32') +    elif byte == 68: +        const, offset, dummy = Read(expr, offset, 'uint64') +    elif byte == 35: +        pass +    else: +        raise Exception(Colors.red + "illegal opcode for an MVP init expr." + Colors.ENDC) + +    block_end, offset, dummy = Read(expr, offset, 'uint8') +    if block_end != 11: +        raise Exception(Colors.red + "init expr has no block end." + Colors.ENDC) + +    return(const) + +# reads different-typed values from a byte array, takes in the bytearray, the +# current offset the read should be performed from and the kind of value that +# should be read. returns the read value as a decimal number, the updated +# offset and the number of bytes read +def Read(section_byte, offset, kind): +    operand = [] +    return_list = int() +    read_bytes = 0 + +    if kind == 'varuint1' or kind == 'varuint7' or kind == 'varuint32' or kind == 'varuint64': +        while True: +            byte = int(section_byte[offset]) +            read_bytes += 1 +            offset += 1 + +            operand.append(byte) + +            if byte == 0x80: +                pass +            elif byte & 0x80 != 0: +                pass +            else: +                # we have read the last byte of the operand +                break + +        return_list = LEB128UnsignedDecode(operand) +        operand = [] +    elif kind == 'uint8' or kind == 'uint16' or kind == 'uint32' or kind == 'uint64': +        byte = section_byte[offset: offset + TypeDic[kind]] +        read_bytes += TypeDic[kind] +        offset += TypeDic[kind] +        operand.append(byte) +        return_list = int.from_bytes(operand[0], byteorder='little', signed=False) +        operand = [] +    elif kind == 'varint1' or kind == 'varint7' or kind == 'varint32' or kind == 'varint64': +        while True: +            byte = int(section_byte[offset]) +            read_bytes += 1 +            offset += 1 +            operand.append(byte) +            # @DEVI-what happens when we decode a 56-bit value? +            if byte == 0x80 or byte == 0xff: +                pass +            elif byte & 0x80 != 0: +                pass +            else: +                # we have read the lasy byte of the operand +                break +        return_list = LEB128SignedDecode(operand) +        operand = [] +    return return_list, offset, read_bytes + +def ror(val, type_length, rot_size): +    rot_size_rem = rot_size % type_length +    return (((val >> rot_size_rem) & (2**type_length - 1)) | ((val & (2**rot_size_rem - 1)) << (type_length - rot_size_rem))) + +def rol(val, type_length, rot_size): +    rot_size_rem = rot_size % type_length +    return (((val << rot_size_rem) & (2**type_length - 1)) | ((val & ((2**type_length - 1) - (2**(type_length - rot_size_rem) - 1))) >> (type_length - rot_size_rem))) + +# @DEVI-these are here because i wanted to test them to make sure what i thik is +# happening is really happening +def reinterpretf32toi32(val): +    return (stc.unpack("i", stc.pack("f" ,val))[0]) + +def reinterpretf64toi64(val): +    return (stc.unpack("Q", stc.pack("d", val))[0]) + +def reinterpreti32tof32(val): +    return (stc.unpack("f", stc.pack("i", val))[0]) + +def reinterpreti64tof64(val): +    return (stc.unpack("d", stc.pack("Q", val))[0]) + +# @DEVI-FIXME +def clz(val, _type): +    cnt = int() +    if _type == 'uint32': +        bits = np.uint32(val) +        power = 31 +        while power > -1: +            if val & 2**power == 0: +                cnt += 1 +            else: +                break +            power -= 1 +    elif _type == 'uint64': +        bits = bin(np.uint64(val)) +        power = 63 +        while power > -1: +            if val & 2**power == 0: +                cnt += 1 +            else: +                break +            power -= 1 +    else: +        raise Exception(Colors.red + "unsupported type passed to clz." + Colors.ENDC) +    return cnt + + +# @DEVI-FIXME +def ctz(val, _type): +    cnt = int() +    power = int() +    if _type == 'uint32': +        bits = np.uint32(val) +        while power < 32: +            if val & 2**power == 0: +                cnt += 1 +            else: +                break +            power += 1 +    elif _type == 'uint64': +        bits = bin(np.uint64(val)) +        while power < 64: +            if val & 2**power == 0: +                cnt += 1 +            else: +                break +            power += 1 +    else: +        raise Exception(Colors.red + "unsupported type passed to ctz." + Colors.ENDC) +    return cnt + +# @DEVI-FIXME +def pop_cnt(val, _type): +    cnt = int() +    power = int() +    if _type == 'uint32': +        bits = np.uint32(val) +        while power < 32: +            if val & 2**power != 0: +                cnt += 1 +            power += 1 +    elif _type == 'uint64': +        bits = bin(np.uint64(val)) +        while power < 64: +            if val & 2**power != 0: +                cnt += 1 +        power += 1 +    else: +        raise Exception(Colors.red + "unsupported type passed to pop_cnt." + Colors.ENDC) +    return cnt + +def gen_label(label_stack): +    counter += 1 +    label_stack.append(counter) + +def dumpprettysections(sections_list, width, section_name): +    line_counter = 0 +    str_list = [] +    module_counter = 0 +    section_offset = 0 +    for sections in sections_list: +        print (Colors.cyan + Colors.BOLD + "module " + repr(module_counter) + Colors.ENDC) +        for section in sections.section_list: +            if section_name == "": pass +            else: +                if section_name != SectionID[section[0]]: +                    continue +            print(Colors.green + Colors.BOLD + SectionID[section[0]] + " section" + Colors.ENDC) +            #print(Colors.green + "length: " + Colors.blue + section[1] + Colors.ENDC) +            print(Colors.green + "length: " + Colors.blue + repr(section[2]) + Colors.ENDC) +            print(Colors.green + "is custom section: " + Colors.blue + repr(section[3]) + Colors.ENDC) +            print(Colors.green + "name length: " + Colors.blue + repr(section[4]) + Colors.ENDC) +            print(Colors.green + "name: " + Colors.blue + section[5] + Colors.ENDC) +            print("\t", end="") +            for offset in range(0, width): +                if offset <= 15: +                    print(Colors.yellow + hex(offset) + "  " + Colors.ENDC, end="") +                else: +                    print(Colors.yellow + hex(offset) + " " + Colors.ENDC, end="") +            print() +            print(Colors.yellow + Colors.BOLD + hex(section_offset) + "\t" + Colors.ENDC, end="") +            for byte in section[6]: +                if line_counter == width: +                    section_offset += width +                    #print("\t\t", end="") +                    line_counter = 0 +                    for char in str_list: +                        print(Colors.green + "|" + Colors.ENDC, end="") +                        if ord(char) < 32: print(" ", end="") +                        else:  print(char, end="") +                    str_list = [] +                    print() +                    print(Colors.yellow + Colors.BOLD + hex(section_offset) + "\t" + Colors.ENDC, end="") +                print(format(byte, '02x') + "   ", end="") +                str_list.append(chr(byte)) +                line_counter += 1 +            #print("  ", end="") +            for i in range(0, width - line_counter): print("     ", end="") +            for char in str_list: +                if ord(char) < 32: print(" ", end="") +                else:  print(char, end="") +                print(Colors.green + "|" + Colors.ENDC, end="") +            str_list = [] +            line_counter = 0 +            section_offset = 0 +            print() +        str_list = [] +        line_counter = 0 +        module_counter += 1 +        section_offset = 0 + +def popcnt32(r1): +    temp = r1 +    temp = (temp & 0x55555555) + ((temp >> 1) & 0x55555555) +    temp = (temp & 0x33333333) + ((temp >> 2) & 0x33333333) +    temp = (temp & 0x0f0f0f0f) + ((temp >> 4) & 0x0f0f0f0f) +    temp = (temp & 0x00ff00ff) + ((temp >> 8) & 0x00ff00ff) +    temp = (temp & 0x0000ffff) + ((temp >> 16) & 0x0000ffff) +    return temp + +def popcnt64(r1): +    temp = r1 +    temp = (temp & 0x5555555555555555) + ((temp >> 1) & 0x5555555555555555) +    temp = (temp & 0x3333333333333333) + ((temp >> 2) & 0x3333333333333333) +    temp = (temp & 0x0f0f0f0f0f0f0f0f) + ((temp >> 4) & 0x0f0f0f0f0f0f0f0f) +    temp = (temp & 0x00ff00ff00ff00ff) + ((temp >> 8) & 0x00ff00ff00ff00ff) +    temp = (temp & 0x0000ffff0000ffff) + ((temp >> 16) & 0x0000ffff0000ffff) +    temp = (temp & 0x00000000ffffffff) + ((temp >> 32) & 0x00000000ffffffff) +    return temp + +def clz32(r1): +    if r1 == 0: return 32 +    temp_r1 = r1 +    n = 0 +    if temp_r1 & 0xffff0000 == 0: +        n += 16 +        temp_r1 = temp_r1 << 16 +    if temp_r1 & 0xff000000 == 0: +        n += 8 +        temp_r1 = temp_r1 << 8 +    if temp_r1 & 0xf0000000 == 0: +        n += 4 +        temp_r1 = temp_r1 << 4 +    if temp_r1 & 0xc0000000 == 0: +        n += 2 +        temp_r1 = temp_r1 << 2 +    if temp_r1 & 0x8000000 == 0: +        n += 1 +    return n + +def clz64(r1): +    if r1 == 0: return 64 +    temp_r1 = r1 +    n = 0 +    if temp_r1 & 0xffffffff00000000 == 0: +        n += 32 +        temp_r1 = temp_r1 << 32 +    if temp_r1 & 0xffff000000000000 == 0: +        n += 16 +        temp_r1 == temp_r1 << 16 +    if temp_r1 & 0xff00000000000000 == 0: +        n+= 8 +        temp_r1 = temp_r1 << 8 +    if temp_r1 & 0xf000000000000000 == 0: +        n += 4 +        temp_r1 = temp_r1 << 4 +    if temp_r1 & 0xc000000000000000 == 0: +        n += 2 +        temp_r1 = temp_r1 << 2 +    if temp_r1 & 0x8000000000000000 == 0: +        n += 1 +    return n + +def ctz32(r1): +    if r1 == 0: return 32 +    temp_r1 = r1 +    n = 0 +    if temp_r1 & 0x0000ffff == 0: +        n += 16 +        temp_r1 = temp_r1 >> 16 +    if temp_r1 & 0x000000ff == 0: +        n += 8 +        temp_r1 = temp_r1 >> 8 +    if temp_r1 & 0x0000000f == 0: +        n += 4 +        temp_r1 = temp_r1 >> 4 +    if temp_r1 & 0x00000003 == 0: +        n += 2 +        temp_r1 = temp_r1 >> 2 +    if temp_r1 & 0x00000001 == 0: +        n += 1 +    return n + +def ctz64(r1): +    if r1 == 0: return 64 +    temp_r1 = r1 +    n = 0 +    if temp_r1 & 0x00000000ffffffff == 0: +        n += 32 +        temp_r1 = temp_r1 >> 32 +    if temp_r1 & 0x000000000000ffff == 0: +        n += 16 +        temp_r1 = temp_r1 >> 16 +    if temp_r1 & 0x00000000000000ff == 0: +        n += 8 +        temp_r1 = temp_r1 >> 8 +    if temp_r1 & 0x000000000000000f == 0: +        n += 4 +        temp_r1 = temp_r1 >> 4 +    if temp_r1 & 0x0000000000000003 == 0: +        n += 2 +        temp_r1 = temp_r1 >> 2 +    if temp_r1 & 0x0000000000000001 == 0: +        n += 1 +    return n | 
