diff --git a/docs/lua/tables/memory.md b/docs/lua/tables/memory.md index f4fbe537..c5cc3694 100644 --- a/docs/lua/tables/memory.md +++ b/docs/lua/tables/memory.md @@ -2,7 +2,7 @@ Table containing helper functions related to process memory. -## Functions (6) +## Functions (7) ### `scan_pattern(pattern)` @@ -73,6 +73,7 @@ memory.free(ptr) **Example Usage:** ```lua local ptr = memory.scan_pattern("some ida sig") +-- Check the implementation of the asmjit::TypeId get_type_id function if you are unsure what to use for return type / parameters types memory.dynamic_hook("test_hook", "float", {"const char*"}, ptr, function(ret_val, str) @@ -103,4 +104,43 @@ end) memory.dynamic_hook(hook_name, return_type, param_types, target_func_ptr, pre_callback, post_callback) ``` +### `dynamic_call(return_type, param_types, target_func_ptr)` + +**Example Usage:** +```lua +-- the sig in this example leads to an implementation of memcpy_s +local ptr = memory.scan_pattern("48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 49 8B D9 49 8B F0 48 8B FA") +if ptr:is_valid() then + local dest_size = 8 + local dest_ptr = memory.allocate(dest_size) + dest_ptr:set_qword(0) + + local src_size = 8 + local src_ptr = memory.allocate(src_size) + src_ptr:set_qword(123) + + -- Check the implementation of the asmjit::TypeId get_type_id function if you are unsure what to use for return type / parameters types + local func_to_call_test_global_name = memory.dynamic_call("int", {"void*", "uint64_t", "void*", "uint64_t"}, ptr) + -- print zero. + log.info(dest_ptr:get_qword()) + -- note: don't pass memory.pointer objects directly when you call the function, but use get_address() instead. + local call_res_test = _G[func_to_call_test_global_name](dest_ptr:get_address(), dest_size, src_ptr:get_address(), src_size) + -- print 123. + log.info(dest_ptr:get_qword()) +end +``` + +- **Parameters:** + - `return_type` (string): Type of the return value of the function to call. + - `param_types` (table): Types of the parameters of the function to call. + - `target_func_ptr` (memory.pointer): The pointer to the function to call. + +- **Returns:** + - `string`: Key name of the function that you can now call from lua. + +**Example Usage:** +```lua +string = memory.dynamic_call(return_type, param_types, target_func_ptr) +``` + diff --git a/src/lua/bindings/memory.cpp b/src/lua/bindings/memory.cpp index f9b7ac2d..af76f3d2 100644 --- a/src/lua/bindings/memory.cpp +++ b/src/lua/bindings/memory.cpp @@ -216,6 +216,7 @@ namespace lua::memory // **Example Usage:** // ```lua // local ptr = memory.scan_pattern("some ida sig") + // -- Check the implementation of the asmjit::TypeId get_type_id function if you are unsure what to use for return type / parameters types // memory.dynamic_hook("test_hook", "float", {"const char*"}, ptr, // function(ret_val, str) // @@ -270,6 +271,351 @@ namespace lua::memory } } + static std::unordered_map> jitted_binded_funcs; + + static std::string get_jitted_lua_func_global_name(uintptr_t function_to_call_ptr) + { + return std::format("__dynamic_call_{}", function_to_call_ptr); + } + + class asmjit_error_handler_t : public asmjit::ErrorHandler + { + public: + void handleError(asmjit::Error err, const char* message, asmjit::BaseEmitter* origin) override + { + LOG(FATAL) << "asmjit error: " << message; + } + }; + + static void jit_lua_binded_func(uintptr_t function_to_call_ptr, const asmjit::FuncSignature& function_to_call_sig, const asmjit::Arch& arch, std::vector param_types, type_info_t return_type, lua_State* lua_state, const std::string& jitted_lua_func_global_name) + { + const auto it = jitted_binded_funcs.find(function_to_call_ptr); + if (it != jitted_binded_funcs.end()) + { + return; + } + + asmjit::CodeHolder code; + auto env = asmjit::Environment::host(); + env.setArch(arch); + auto asmjit_error = code.init(env); + + // initialize function + asmjit::x86::Compiler cc(&code); + // clang-format off + asmjit::FuncNode* func = cc.addFunc(asmjit::FuncSignature(asmjit::CallConvId::kFastCall, asmjit::FuncSignature::kNoVarArgs, + asmjit::TypeId::kInt32, + asmjit::TypeId::kUIntPtr)); + // clang-format on + + asmjit::StringLogger log; + // clang-format off + const auto format_flags = + asmjit::FormatFlags::kMachineCode | asmjit::FormatFlags::kExplainImms | asmjit::FormatFlags::kRegCasts | + asmjit::FormatFlags::kHexImms | asmjit::FormatFlags::kHexOffsets | asmjit::FormatFlags::kPositions; + // clang-format on + + log.addFlags(format_flags); + code.setLogger(&log); + asmjit_error_handler_t asmjit_error_handler; + code.setErrorHandler(&asmjit_error_handler); + + // too small to really need it + func->frame().resetPreservedFP(); + + // map argument slots to registers, following abi. + std::vector arg_registers; + for (uint8_t arg_index = 0; arg_index < function_to_call_sig.argCount(); arg_index++) + { + const auto arg_type = function_to_call_sig.args()[arg_index]; + + // for each "function to call" parameter + // InvokeNode for the corresponding lua_toXXX func + // result of the invokenode setRet goes to the arg Reg. + // those Reg will then be setArg of the function_to_call final InvokeNode. + + asmjit::x86::Reg arg; + + const auto arg_type_info = param_types[arg_index]; + if (arg_type_info == type_info_t::integer_ || arg_type_info == type_info_t::float_ || arg_type_info == type_info_t::double_) + { + asmjit::InvokeNode* lua_tofunc; + // clang-format off + cc.invoke(&lua_tofunc, lua_tonumberx, asmjit::FuncSignature(asmjit::CallConvId::kCDecl, asmjit::FuncSignature::kNoVarArgs, + asmjit::TypeId::kFloat64, + asmjit::TypeId::kUIntPtr, asmjit::TypeId::kInt32, asmjit::TypeId::kUIntPtr)); + // clang-format on + + lua_tofunc->setArg(0, lua_state); + lua_tofunc->setArg(1, arg_index + 1); + lua_tofunc->setArg(2, NULL); + + const auto tmp = cc.newXmm(); + lua_tofunc->setRet(0, tmp); + if (arg_type_info == type_info_t::integer_) + { + arg = cc.newUIntPtr(); + cc.cvttsd2si(arg.as(), tmp); + } + else if (arg_type_info == type_info_t::float_) + { + arg = cc.newXmm(); + cc.cvtsd2ss(arg.as(), tmp); + } + else + { + arg = tmp; + } + } + else if (arg_type_info == type_info_t::boolean_) + { + asmjit::InvokeNode* lua_tofunc; + // clang-format off + cc.invoke(&lua_tofunc, lua_toboolean, asmjit::FuncSignature(asmjit::CallConvId::kCDecl, asmjit::FuncSignature::kNoVarArgs, + asmjit::TypeId::kInt32, + asmjit::TypeId::kUIntPtr, asmjit::TypeId::kInt32)); + // clang-format on + + lua_tofunc->setArg(0, lua_state); + lua_tofunc->setArg(1, arg_index + 1); + + arg = cc.newUIntPtr(); + lua_tofunc->setRet(0, arg); + } + else if (arg_type_info == type_info_t::string_) + { + asmjit::InvokeNode* lua_tofunc; + // clang-format off + cc.invoke(&lua_tofunc, lua_tolstring, asmjit::FuncSignature(asmjit::CallConvId::kCDecl, asmjit::FuncSignature::kNoVarArgs, + asmjit::TypeId::kUIntPtr, + asmjit::TypeId::kUIntPtr, asmjit::TypeId::kInt32, asmjit::TypeId::kUIntPtr)); + // clang-format on + + lua_tofunc->setArg(0, lua_state); + lua_tofunc->setArg(1, arg_index + 1); + lua_tofunc->setArg(2, NULL); + + arg = cc.newUIntPtr(); + lua_tofunc->setRet(0, arg); + } + else if (arg_type_info == type_info_t::ptr_) + { + asmjit::InvokeNode* lua_tofunc; + // clang-format off + cc.invoke(&lua_tofunc, lua_tonumberx, asmjit::FuncSignature(asmjit::CallConvId::kCDecl, asmjit::FuncSignature::kNoVarArgs, + asmjit::TypeId::kFloat64, + asmjit::TypeId::kUIntPtr, asmjit::TypeId::kInt32, asmjit::TypeId::kUIntPtr)); + // clang-format on + + lua_tofunc->setArg(0, lua_state); + lua_tofunc->setArg(1, arg_index + 1); + lua_tofunc->setArg(2, NULL); + + // lua_Number (double) to integer type + const auto tmp = cc.newXmm(); + lua_tofunc->setRet(0, tmp); + arg = cc.newUIntPtr(); + cc.cvttsd2si(arg.as(), tmp); + } + + arg_registers.push_back(arg); + } + + asmjit::InvokeNode* function_to_call_invoke_node; + cc.invoke(&function_to_call_invoke_node, function_to_call_ptr, function_to_call_sig); + for (uint8_t arg_index = 0; arg_index < function_to_call_sig.argCount(); arg_index++) + { + function_to_call_invoke_node->setArg(arg_index, arg_registers.at(arg_index)); + } + asmjit::x86::Reg function_to_call_return_val_reg; + if (is_general_register(function_to_call_sig.ret())) + { + function_to_call_return_val_reg = cc.newUIntPtr(); + } + else if (is_XMM_register(function_to_call_sig.ret())) + { + function_to_call_return_val_reg = cc.newXmm(); + } + else + { + LOG(FATAL) << "Return val wider than 64bits not supported"; + return; + } + function_to_call_invoke_node->setRet(0, function_to_call_return_val_reg); + + if (return_type == type_info_t::integer_ || return_type == type_info_t::float_ || return_type == type_info_t::double_) + { + if (function_to_call_sig.ret() >= asmjit::TypeId::_kIntStart && function_to_call_sig.ret() <= asmjit::TypeId::_kIntEnd) + { + // the function returned to a Gp register, need to convert it to a lua_Number compatible register. + const auto tmp = cc.newXmm(); + cc.cvtsi2sd(tmp, function_to_call_return_val_reg.as()); + function_to_call_return_val_reg = tmp; + } + else if (function_to_call_sig.ret() == asmjit::TypeId::kFloat32) + { + // m128_f32 -> m128_f64 (lua_Number) + cc.cvtss2sd(function_to_call_return_val_reg.as(), function_to_call_return_val_reg.as()); + } + + asmjit::InvokeNode* lua_pushfunc; + // clang-format off + cc.invoke(&lua_pushfunc, lua_pushnumber, asmjit::FuncSignature(asmjit::CallConvId::kCDecl, asmjit::FuncSignature::kNoVarArgs, + asmjit::TypeId::kVoid, + asmjit::TypeId::kUIntPtr, asmjit::TypeId::kFloat64)); + // clang-format on + + lua_pushfunc->setArg(0, lua_state); + lua_pushfunc->setArg(1, function_to_call_return_val_reg); + } + else if (return_type == type_info_t::boolean_) + { + asmjit::InvokeNode* lua_pushfunc; + // clang-format off + cc.invoke(&lua_pushfunc, lua_pushboolean, asmjit::FuncSignature(asmjit::CallConvId::kCDecl, asmjit::FuncSignature::kNoVarArgs, + asmjit::TypeId::kVoid, + asmjit::TypeId::kUIntPtr, asmjit::TypeId::kInt8)); + // clang-format on + + lua_pushfunc->setArg(0, lua_state); + lua_pushfunc->setArg(1, function_to_call_return_val_reg); + } + else if (return_type == type_info_t::string_) + { + asmjit::InvokeNode* lua_pushfunc; + // clang-format off + cc.invoke(&lua_pushfunc, lua_pushstring, asmjit::FuncSignature(asmjit::CallConvId::kCDecl, asmjit::FuncSignature::kNoVarArgs, + asmjit::TypeId::kVoid, + asmjit::TypeId::kUIntPtr, asmjit::TypeId::kUIntPtr)); + // clang-format on + + lua_pushfunc->setArg(0, lua_state); + lua_pushfunc->setArg(1, function_to_call_return_val_reg); + } + else if (return_type == type_info_t::ptr_) + { + // integer type to lua_Number (double) + asmjit::x86::Xmm tmp = cc.newXmm(); + cc.cvtsi2sd(tmp, function_to_call_return_val_reg.as()); + + asmjit::InvokeNode* lua_pushfunc; + // clang-format off + cc.invoke(&lua_pushfunc, lua_pushnumber, asmjit::FuncSignature(asmjit::CallConvId::kCDecl, asmjit::FuncSignature::kNoVarArgs, + asmjit::TypeId::kVoid, + asmjit::TypeId::kUIntPtr, asmjit::TypeId::kFloat64)); + // clang-format on + + lua_pushfunc->setArg(0, lua_state); + lua_pushfunc->setArg(1, tmp); + } + + // a lua binded c func always return an int which hold the number of returned vars. + asmjit::x86::Gp retReg = cc.newUIntPtr(); + cc.mov(retReg, function_to_call_sig.hasRet() ? 1 : 0); + cc.ret(retReg); + + cc.endFunc(); + + // write to buffer + cc.finalize(); + + // worst case, overestimates for case trampolines needed + code.flatten(); + size_t size = code.codeSize(); + + // Allocate a virtual memory (executable). + static std::vector jit_function_buffer(size); + DWORD old_protect; + VirtualProtect(jit_function_buffer.data(), size, PAGE_EXECUTE_READWRITE, &old_protect); + + // if multiple sections, resolve linkage (1 atm) + if (code.hasUnresolvedLinks()) + { + code.resolveUnresolvedLinks(); + } + + // Relocate to the base-address of the allocated memory. + code.relocateToBase((uintptr_t)jit_function_buffer.data()); + code.copyFlattenedData(jit_function_buffer.data(), size); + + LOG(VERBOSE) << "JIT Stub: " << log.data(); + + lua_pushcfunction(lua_state, (lua_CFunction)jit_function_buffer.data()); + lua_setglobal(lua_state, jitted_lua_func_global_name.c_str()); + } + + // Lua API: Function + // Table: memory + // Name: dynamic_call + // Param: return_type: string: Type of the return value of the function to call. + // Param: param_types: table: Types of the parameters of the function to call. + // Param: target_func_ptr: memory.pointer: The pointer to the function to call. + // Returns: string: Key name of the function that you can now call from lua. + // **Example Usage:** + // ```lua + // -- the sig in this example leads to an implementation of memcpy_s + // local ptr = memory.scan_pattern("48 89 5C 24 08 48 89 74 24 10 57 48 83 EC 20 49 8B D9 49 8B F0 48 8B FA") + // if ptr:is_valid() then + // local dest_size = 8 + // local dest_ptr = memory.allocate(dest_size) + // dest_ptr:set_qword(0) + // + // local src_size = 8 + // local src_ptr = memory.allocate(src_size) + // src_ptr:set_qword(123) + // + // -- Check the implementation of the asmjit::TypeId get_type_id function if you are unsure what to use for return type / parameters types + // local func_to_call_test_global_name = memory.dynamic_call("int", {"void*", "uint64_t", "void*", "uint64_t"}, ptr) + // -- print zero. + // log.info(dest_ptr:get_qword()) + // -- note: don't pass memory.pointer objects directly when you call the function, but use get_address() instead. + // local call_res_test = _G[func_to_call_test_global_name](dest_ptr:get_address(), dest_size, src_ptr:get_address(), src_size) + // -- print 123. + // log.info(dest_ptr:get_qword()) + // end + // ``` + static std::string dynamic_call(const std::string& return_type, sol::table param_types_table, lua::memory::pointer& target_func_ptr_obj, sol::this_state state_) + { + const auto target_func_ptr = target_func_ptr_obj.get_address(); + + const auto jitted_lua_func_global_name = get_jitted_lua_func_global_name(target_func_ptr); + + const auto already_jitted_func = sol::state_view(state_)[jitted_lua_func_global_name]; + if (already_jitted_func.is()) + { + return already_jitted_func; + } + + std::vector param_types_strings; + for (const auto& [k, v] : param_types_table) + { + if (v.is()) + { + param_types_strings.push_back(v.as()); + } + } + + std::string call_convention = ""; + asmjit::FuncSignature sig(get_call_convention(call_convention), asmjit::FuncSignature::kNoVarArgs, get_type_id(return_type)); + + std::vector param_types; + for (const std::string& s : param_types_strings) + { + sig.addArg(get_type_id(s)); + param_types.push_back(get_type_info_from_string(s)); + } + + jit_lua_binded_func(target_func_ptr, + sig, + asmjit::Arch::kHost, + param_types, + get_type_info_from_string(return_type), + state_.L, + jitted_lua_func_global_name); + + return jitted_lua_func_global_name; + } + void bind(sol::state& state) { auto ns = state["memory"].get_or_create(); @@ -312,5 +658,7 @@ namespace lua::memory ns.new_usertype("value_wrapper", "get", &value_wrapper_t::get, "set", &value_wrapper_t::set); ns["dynamic_hook"] = dynamic_hook; + + ns["dynamic_call"] = dynamic_call; } } \ No newline at end of file diff --git a/src/lua/bindings/runtime_func_t.hpp b/src/lua/bindings/runtime_func_t.hpp index 5eeabfeb..c35d1d52 100644 --- a/src/lua/bindings/runtime_func_t.hpp +++ b/src/lua/bindings/runtime_func_t.hpp @@ -6,6 +6,143 @@ namespace lua::memory { + // does a given type fit in a general purpose register (i.e. is it integer type) + inline bool is_general_register(const asmjit::TypeId type_id) + { + switch (type_id) + { + case asmjit::TypeId::kInt8: + case asmjit::TypeId::kUInt8: + case asmjit::TypeId::kInt16: + case asmjit::TypeId::kUInt16: + case asmjit::TypeId::kInt32: + case asmjit::TypeId::kUInt32: + case asmjit::TypeId::kInt64: + case asmjit::TypeId::kUInt64: + case asmjit::TypeId::kIntPtr: + case asmjit::TypeId::kUIntPtr: return true; + default: return false; + } + } + + // float, double, simd128 + inline bool is_XMM_register(const asmjit::TypeId type_id) + { + switch (type_id) + { + case asmjit::TypeId::kFloat32: + case asmjit::TypeId::kFloat64: return true; + default: return false; + } + } + + inline asmjit::CallConvId get_call_convention(const std::string& conv) + { + if (conv == "cdecl") + { + return asmjit::CallConvId::kCDecl; + } + else if (conv == "stdcall") + { + return asmjit::CallConvId::kStdCall; + } + else if (conv == "fastcall") + { + return asmjit::CallConvId::kFastCall; + } + + return asmjit::CallConvId::kHost; + } + + inline asmjit::TypeId get_type_id(const std::string& type) + { + if (type.find('*') != std::string::npos) + { + return asmjit::TypeId::kUIntPtr; + } + +#define TYPEID_MATCH_STR_IF(var, T) \ + if (var == #T) \ + { \ + return asmjit::TypeId(asmjit::TypeUtils::TypeIdOfT::kTypeId); \ + } +#define TYPEID_MATCH_STR_ELSEIF(var, T) \ + else if (var == #T) \ + { \ + return asmjit::TypeId(asmjit::TypeUtils::TypeIdOfT::kTypeId); \ + } + + TYPEID_MATCH_STR_IF(type, signed char) + TYPEID_MATCH_STR_ELSEIF(type, unsigned char) + TYPEID_MATCH_STR_ELSEIF(type, short) + TYPEID_MATCH_STR_ELSEIF(type, unsigned short) + TYPEID_MATCH_STR_ELSEIF(type, int) + TYPEID_MATCH_STR_ELSEIF(type, unsigned int) + TYPEID_MATCH_STR_ELSEIF(type, long) + TYPEID_MATCH_STR_ELSEIF(type, unsigned long) +#ifdef POLYHOOK2_OS_WINDOWS + TYPEID_MATCH_STR_ELSEIF(type, __int64) + TYPEID_MATCH_STR_ELSEIF(type, unsigned __int64) +#endif + TYPEID_MATCH_STR_ELSEIF(type, long long) + TYPEID_MATCH_STR_ELSEIF(type, unsigned long long) + TYPEID_MATCH_STR_ELSEIF(type, char) + TYPEID_MATCH_STR_ELSEIF(type, char16_t) + TYPEID_MATCH_STR_ELSEIF(type, char32_t) + TYPEID_MATCH_STR_ELSEIF(type, wchar_t) + TYPEID_MATCH_STR_ELSEIF(type, uint8_t) + TYPEID_MATCH_STR_ELSEIF(type, int8_t) + TYPEID_MATCH_STR_ELSEIF(type, uint16_t) + TYPEID_MATCH_STR_ELSEIF(type, int16_t) + TYPEID_MATCH_STR_ELSEIF(type, int32_t) + TYPEID_MATCH_STR_ELSEIF(type, uint32_t) + TYPEID_MATCH_STR_ELSEIF(type, uint64_t) + TYPEID_MATCH_STR_ELSEIF(type, int64_t) + TYPEID_MATCH_STR_ELSEIF(type, float) + TYPEID_MATCH_STR_ELSEIF(type, double) + TYPEID_MATCH_STR_ELSEIF(type, bool) + TYPEID_MATCH_STR_ELSEIF(type, void) + else if (type == "intptr_t") + { + return asmjit::TypeId::kIntPtr; + } + else if (type == "uintptr_t") + { + return asmjit::TypeId::kUIntPtr; + } + + return asmjit::TypeId::kVoid; + } + + static type_info_t get_type_info_from_string(const std::string& s) + { + if ((s.contains("const") && s.contains("char") && s.contains("*")) || s.contains("string")) + { + return type_info_t::string_; + } + else if (s.contains("bool")) + { + return type_info_t::boolean_; + } + else if (s.contains("ptr") || s.contains("pointer") || s.contains("*")) + { + // passing lua::memory::pointer + return type_info_t::ptr_; + } + else if (s.contains("float")) + { + return type_info_t::float_; + } + else if (s.contains("double")) + { + return type_info_t::double_; + } + else + { + return type_info_t::integer_; + } + } + class runtime_func_t { std::vector m_jit_function_buffer; @@ -317,34 +454,6 @@ namespace lua::memory // stdcall, fastcall, or cdecl (cdecl is default on x86). On x64 those map to the same thing. uintptr_t make_jit_func(const std::string& return_type, const std::vector& param_types, const asmjit::Arch arch, const user_pre_callback_t pre_callback, const user_post_callback_t post_callback, const uintptr_t target_func_ptr, std::string call_convention = "") { - auto get_type_info_from_string = [](const std::string& s) { - if ((s.contains("const") && s.contains("char") && s.contains("*")) || s.contains("string")) - { - return type_info_t::string_; - } - else if (s.contains("bool")) - { - return type_info_t::boolean_; - } - else if (s.contains("ptr") || s.contains("pointer") || s.contains("*")) - { - // passing lua::memory::pointer - return type_info_t::ptr_; - } - else if (s.contains("float")) - { - return type_info_t::float_; - } - else if (s.contains("double")) - { - return type_info_t::double_; - } - else - { - return type_info_t::integer_; - } - }; - m_return_type = get_type_info_from_string(return_type); asmjit::FuncSignature sig(get_call_convention(call_convention), asmjit::FuncSignature::kNoVarArgs, get_type_id(return_type)); @@ -364,114 +473,5 @@ namespace lua::memory m_detour->enable(); } - - private: - // does a given type fit in a general purpose register (i.e. is it integer type) - bool is_general_register(const asmjit::TypeId type_id) const - { - switch (type_id) - { - case asmjit::TypeId::kInt8: - case asmjit::TypeId::kUInt8: - case asmjit::TypeId::kInt16: - case asmjit::TypeId::kUInt16: - case asmjit::TypeId::kInt32: - case asmjit::TypeId::kUInt32: - case asmjit::TypeId::kInt64: - case asmjit::TypeId::kUInt64: - case asmjit::TypeId::kIntPtr: - case asmjit::TypeId::kUIntPtr: return true; - default: return false; - } - } - - // float, double, simd128 - bool is_XMM_register(const asmjit::TypeId type_id) const - { - switch (type_id) - { - case asmjit::TypeId::kFloat32: - case asmjit::TypeId::kFloat64: return true; - default: return false; - } - } - - asmjit::CallConvId get_call_convention(const std::string& conv) - { - if (conv == "cdecl") - { - return asmjit::CallConvId::kCDecl; - } - else if (conv == "stdcall") - { - return asmjit::CallConvId::kStdCall; - } - else if (conv == "fastcall") - { - return asmjit::CallConvId::kFastCall; - } - - return asmjit::CallConvId::kHost; - } - - asmjit::TypeId get_type_id(const std::string& type) - { - if (type.find('*') != std::string::npos) - { - return asmjit::TypeId::kUIntPtr; - } - -#define TYPEID_MATCH_STR_IF(var, T) \ - if (var == #T) \ - { \ - return asmjit::TypeId(asmjit::TypeUtils::TypeIdOfT::kTypeId); \ - } -#define TYPEID_MATCH_STR_ELSEIF(var, T) \ - else if (var == #T) \ - { \ - return asmjit::TypeId(asmjit::TypeUtils::TypeIdOfT::kTypeId); \ - } - - TYPEID_MATCH_STR_IF(type, signed char) - TYPEID_MATCH_STR_ELSEIF(type, unsigned char) - TYPEID_MATCH_STR_ELSEIF(type, short) - TYPEID_MATCH_STR_ELSEIF(type, unsigned short) - TYPEID_MATCH_STR_ELSEIF(type, int) - TYPEID_MATCH_STR_ELSEIF(type, unsigned int) - TYPEID_MATCH_STR_ELSEIF(type, long) - TYPEID_MATCH_STR_ELSEIF(type, unsigned long) -#ifdef POLYHOOK2_OS_WINDOWS - TYPEID_MATCH_STR_ELSEIF(type, __int64) - TYPEID_MATCH_STR_ELSEIF(type, unsigned __int64) -#endif - TYPEID_MATCH_STR_ELSEIF(type, long long) - TYPEID_MATCH_STR_ELSEIF(type, unsigned long long) - TYPEID_MATCH_STR_ELSEIF(type, char) - TYPEID_MATCH_STR_ELSEIF(type, char16_t) - TYPEID_MATCH_STR_ELSEIF(type, char32_t) - TYPEID_MATCH_STR_ELSEIF(type, wchar_t) - TYPEID_MATCH_STR_ELSEIF(type, uint8_t) - TYPEID_MATCH_STR_ELSEIF(type, int8_t) - TYPEID_MATCH_STR_ELSEIF(type, uint16_t) - TYPEID_MATCH_STR_ELSEIF(type, int16_t) - TYPEID_MATCH_STR_ELSEIF(type, int32_t) - TYPEID_MATCH_STR_ELSEIF(type, uint32_t) - TYPEID_MATCH_STR_ELSEIF(type, uint64_t) - TYPEID_MATCH_STR_ELSEIF(type, int64_t) - TYPEID_MATCH_STR_ELSEIF(type, float) - TYPEID_MATCH_STR_ELSEIF(type, double) - TYPEID_MATCH_STR_ELSEIF(type, bool) - TYPEID_MATCH_STR_ELSEIF(type, void) - else if (type == "intptr_t") - { - return asmjit::TypeId::kIntPtr; - } - else if (type == "uintptr_t") - { - return asmjit::TypeId::kUIntPtr; - } - - return asmjit::TypeId::kVoid; - } }; } \ No newline at end of file