// p = process.open(command) tb_int_t xm_process_open(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); // get the command size_t command_size = 0; tb_char_t const* command = luaL_checklstring(lua, 1, &command_size); tb_char_t const* outfile = lua_tostring(lua, 2); tb_char_t const* errfile = lua_tostring(lua, 3); tb_check_return_val(command, 0); // init attributes tb_process_attr_t attr = {0}; // redirect stdout? if (outfile) { // redirect stdout to file attr.outfile = outfile; attr.outmode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_APPEND; // remove the outfile first if (tb_file_info(outfile, tb_null)) tb_file_remove(outfile); } // redirect stderr? if (errfile) { // redirect stderr to file attr.errfile = errfile; attr.errmode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_APPEND; // remove the errfile first if (tb_file_info(errfile, tb_null)) tb_file_remove(errfile); } // init process tb_process_ref_t process = tb_process_init_cmd(command, &attr); // save the process reference lua_pushlightuserdata(lua, process); // ok return 1; }
tb_int_t xm_machine_main(xm_machine_ref_t machine, tb_int_t argc, tb_char_t** argv) { // check xm_machine_impl_t* impl = (xm_machine_impl_t*)machine; tb_assert_and_check_return_val(impl && impl->lua, -1); // save main arguments to the global variable: _ARGV if (!xm_machine_main_save_arguments(impl, argc, argv)) return -1; // get the project directory tb_char_t path[TB_PATH_MAXN] = {0}; if (!xm_machine_main_get_project_directory(impl, path, sizeof(path))) return -1; // get the program directory if (!xm_machine_main_get_program_directory(impl, path, sizeof(path))) return -1; // append the main script path tb_strcat(path, "/core/_xmake_main.lua"); // exists this script? if (!tb_file_info(path, tb_null)) { // error tb_printf("not found main script: %s\n", path); // failed return -1; } // trace tb_trace_d("main: %s", path); // load and execute the main script if (luaL_dofile(impl->lua, path)) { // error tb_printf("error: %s\n", lua_tostring(impl->lua, -1)); // failed return -1; } // set the error function lua_getglobal(impl->lua, "debug"); lua_getfield(impl->lua, -1, "traceback"); // call the main function lua_getglobal(impl->lua, "_xmake_main"); if (lua_pcall(impl->lua, 0, 1, -2)) { // error tb_printf("error: %s\n", lua_tostring(impl->lua, -1)); // failed return -1; } // get the error code return (tb_int_t)lua_tonumber(impl->lua, -1); }
tb_bool_t tb_directory_copy(tb_char_t const* path, tb_char_t const* dest) { // the absolute path tb_char_t full0[TB_PATH_MAXN]; path = tb_path_absolute(path, full0, TB_PATH_MAXN); tb_assert_and_check_return_val(path, tb_false); // the dest path tb_char_t full1[TB_PATH_MAXN]; dest = tb_path_absolute(dest, full1, TB_PATH_MAXN); tb_assert_and_check_return_val(dest, tb_false); // walk copy tb_value_t tuple[3]; tuple[0].cstr = dest; tuple[1].ul = tb_strlen(path); tuple[2].b = tb_true; tb_directory_walk(path, -1, tb_true, tb_directory_walk_copy, tuple); // ok? tb_bool_t ok = tuple[2].b; // copy empty directory? if (ok && !tb_file_info(dest, tb_null)) return tb_directory_create(dest); // ok? return ok; }
static tb_bool_t tb_directory_walk_impl(tb_char_t const* path, tb_bool_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv) { // check tb_assert_and_check_return_val(path && func, tb_false); // last tb_long_t last = tb_strlen(path) - 1; tb_assert_and_check_return_val(last >= 0, tb_false); // done tb_bool_t ok = tb_true; tb_char_t temp[4096] = {0}; DIR* directory = tb_null; if ((directory = opendir(path))) { // walk struct dirent* item = tb_null; while ((item = readdir(directory))) { // check tb_assert_and_check_continue(item->d_reclen); // the item name tb_char_t name[1024] = {0}; tb_strncpy(name, item->d_name, tb_min(item->d_reclen, sizeof(name) - 1)); if (tb_strcmp(name, ".") && tb_strcmp(name, "..")) { // the temp path tb_long_t n = tb_snprintf(temp, 4095, "%s%s%s", path, path[last] == '/'? "" : "/", name); if (n >= 0) temp[n] = '\0'; // the file info tb_file_info_t info = {0}; if (tb_file_info(temp, &info)) { // do callback if (prefix) ok = func(temp, &info, priv); tb_check_break(ok); // walk to the next directory if (info.type == TB_FILE_TYPE_DIRECTORY && recursion) ok = tb_directory_walk_impl(temp, recursion, prefix, func, priv); tb_check_break(ok); // do callback if (!prefix) ok = func(temp, &info, priv); tb_check_break(ok); } } } // exit directory closedir(directory); } // continue ? return ok; }
/* ////////////////////////////////////////////////////////////////////////////////////// * interfaces */ tb_bool_t tb_dns_init() { // done tb_size_t count = 0; if (tb_file_info("/etc/resolv.conf", tb_null)) { /* try get list from "/etc/resolv.conf" * * # Generated by NetworkManager * nameserver 10.1.20.10 * nameserver 8.8.8.8 * */ tb_stream_ref_t stream = tb_stream_init_from_url("/etc/resolv.conf"); if (stream) { // open if (tb_stream_open(stream)) { // read tb_long_t size = 0; tb_char_t line[8192]; while ((size = tb_stream_bread_line(stream, line, 8192)) >= 0) { if (size && !tb_strnicmp(line, "nameserver", 10)) { // seek to server tb_char_t const* p = line + 10; while (*p && !tb_isdigit(*p)) p++; tb_check_continue(*p); // add server tb_dns_server_add(p); // count++ count++; } } } // exit tb_stream_exit(stream); } } // no server? add the default server if (!count) { tb_dns_server_add("8.8.8.8"); tb_dns_server_add("8.8.8.4"); } // ok return tb_true; }
static tb_void_t tb_directory_walk_impl(tb_wchar_t const* path, tb_bool_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv) { // check tb_assert_and_check_return(path && func); // last tb_long_t last = tb_wcslen(path) - 1; tb_assert_and_check_return(last >= 0); // add \*.* tb_wchar_t temp_w[4096] = {0}; tb_char_t temp_a[4096] = {0}; tb_swprintf(temp_w, 4095, L"%s%s*.*", path, path[last] == L'\\'? L"" : L"\\"); // init info WIN32_FIND_DATAW find = {0}; HANDLE directory = INVALID_HANDLE_VALUE; if (INVALID_HANDLE_VALUE != (directory = FindFirstFileW(temp_w, &find))) { // walk do { // check if (tb_wcscmp(find.cFileName, L".") && tb_wcscmp(find.cFileName, L"..")) { // the temp path tb_long_t n = tb_swprintf(temp_w, 4095, L"%s%s%s", path, path[last] == L'\\'? L"" : L"\\", find.cFileName); if (n >= 0 && n < 4096) temp_w[n] = L'\0'; // wtoa temp n = tb_wtoa(temp_a, temp_w, 4095); if (n >= 0 && n < 4096) temp_a[n] = '\0'; // the file info tb_file_info_t info = {0}; if (tb_file_info(temp_a, &info)) { // do callback if (prefix) func(temp_a, &info, priv); // walk to the next directory if (info.type == TB_FILE_TYPE_DIRECTORY && recursion) tb_directory_walk_impl(temp_w, recursion, prefix, func, priv); // do callback if (!prefix) func(temp_a, &info, priv); } } } while (FindNextFileW(directory, &find)); // exit directory FindClose(directory); } }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_exists(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const* path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // done os.exists(path) lua_pushboolean(lua, tb_file_info(path, tb_null)); // ok return 1; }
/* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_http_server_main(tb_int_t argc, tb_char_t** argv) { // done tb_socket_ref_t sock = tb_null; do { // init socket sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4); tb_assert_and_check_break(sock); // bind socket tb_ipaddr_t addr; tb_ipaddr_set(&addr, tb_null, TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4); if (!tb_socket_bind(sock, &addr)) break; // listen socket if (!tb_socket_listen(sock, 1000)) break; // init the root directory if (argv[1]) tb_strlcpy(g_rootdir, argv[1], sizeof(g_rootdir)); else tb_directory_current(g_rootdir, sizeof(g_rootdir)); // only data? if (!tb_file_info(g_rootdir, tb_null)) g_onlydata = tb_true; // trace tb_trace_i("%s: %s", g_onlydata? "data" : "rootdir", g_rootdir); #if TB_DEMO_CPU > 1 // start workers for multi-threads tb_size_t count = TB_DEMO_CPU - 1; while (count--) tb_thread_init(tb_null, tb_demo_coroutine_worker, sock, 0); #endif // start worker tb_demo_coroutine_worker(sock); } while (0); // exit socket if (sock) tb_socket_exit(sock); sock = tb_null; // ok return 0; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_mkdir(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const* path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // os.mkdir(path) tb_file_info_t info = {0}; if (!tb_file_info(path, &info) || (info.type != TB_FILE_TYPE_DIRECTORY)) lua_pushboolean(lua, tb_directory_create(path)); else lua_pushboolean(lua, tb_true); // ok return 1; }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_int_t xm_os_mtime(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); // get the path tb_char_t const* path = luaL_checkstring(lua, 1); tb_check_return_val(path, 0); // done os.mtime(path) tb_file_info_t info = {0}; if (tb_file_info(path, &info) && (info.type == TB_FILE_TYPE_FILE)) lua_pushinteger(lua, (lua_Integer)info.mtime); else lua_pushinteger(lua, 0); // ok return 1; }
static tb_bool_t tb_directory_walk_copy(tb_char_t const* path, tb_file_info_t const* info, tb_cpointer_t priv) { // check tb_value_t* tuple = (tb_value_t*)priv; tb_assert_and_check_return_val(path && info && tuple, tb_false); // the dest directory tb_char_t const* dest = tuple[0].cstr; tb_assert_and_check_return_val(dest, tb_false); // the file name tb_size_t size = tuple[1].ul; tb_char_t const* name = path + size; // the dest file path tb_char_t dpath[8192] = {0}; tb_snprintf(dpath, 8192, "%s\\%s", dest, name[0] == '\\'? name + 1 : name); // remove the dest file first tb_file_info_t dinfo = {0}; if (tb_file_info(dpath, &dinfo)) { if (dinfo.type == TB_FILE_TYPE_FILE) tb_file_remove(dpath); if (dinfo.type == TB_FILE_TYPE_DIRECTORY) tb_directory_remove(dpath); } // copy switch (info->type) { case TB_FILE_TYPE_FILE: if (!tb_file_copy(path, dpath)) tuple[2].b = tb_false; break; case TB_FILE_TYPE_DIRECTORY: if (!tb_directory_create(dpath)) tuple[2].b = tb_false; break; default: break; } // continue return tb_true; }
tb_void_t tb_directory_walk(tb_char_t const* path, tb_bool_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv) { // check tb_assert_and_check_return(path && func); // exists? tb_file_info_t info = {0}; if (tb_file_info(path, &info) && info.type == TB_FILE_TYPE_DIRECTORY) tb_directory_walk_impl(path, recursion, prefix, func, priv); else { // the absolute path tb_char_t full[TB_PATH_MAXN]; path = tb_path_absolute(path, full, TB_PATH_MAXN); tb_assert_and_check_return(path); // walk tb_directory_walk_impl(path, recursion, prefix, func, priv); } }
tb_void_t tb_directory_walk(tb_char_t const* path, tb_long_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv) { // check tb_assert_and_check_return(path && func); // walk it directly if rootdir is relative path tb_file_info_t info = {0}; if (!tb_path_is_absolute(path) && tb_file_info(path, &info) && info.type == TB_FILE_TYPE_DIRECTORY) { tb_wchar_t path_w[TB_PATH_MAXN]; if (tb_atow(path_w, path, tb_arrayn(path_w)) != -1) tb_directory_walk_impl(path_w, recursion, prefix, func, priv); } else { // the absolute path (translate "~/") tb_wchar_t full_w[TB_PATH_MAXN]; if (tb_path_absolute_w(path, full_w, TB_PATH_MAXN)) tb_directory_walk_impl(full_w, recursion, prefix, func, priv); } }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t tb_directory_create(tb_char_t const* path) { // check tb_assert_and_check_return_val(path, tb_false); // the absolute path tb_char_t full[TB_PATH_MAXN]; path = tb_path_absolute(path, full, TB_PATH_MAXN); tb_assert_and_check_return_val(path, tb_false); // make it tb_bool_t ok = !mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO)? tb_true : tb_false; if (!ok) { // make directory tb_char_t temp[TB_PATH_MAXN] = {0}; tb_char_t const* p = full; tb_char_t* t = temp; tb_char_t const* e = temp + TB_PATH_MAXN - 1; for (; t < e && *p; t++) { *t = *p; if (*p == '/') { // make directory if not exists if (!tb_file_info(temp, tb_null)) mkdir(temp, S_IRWXU | S_IRWXG | S_IRWXO); // skip repeat '/' while (*p && *p == '/') p++; } else p++; } // make it again ok = !mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO)? tb_true : tb_false; } // ok? return ok; }
static tb_bool_t tb_demo_spider_task_done(tb_demo_spider_t* spider, tb_char_t const* iurl, tb_bool_t* full) { // check tb_assert_and_check_return_val(spider && iurl, tb_false); // killed? tb_check_return_val(TB_STATE_OK == tb_atomic_get(&spider->state), tb_false); // only for home? if (spider->home_only && !tb_stristr(iurl, spider->home_domain)) { // trace tb_trace_d("task: done: %s: skip", iurl); return tb_true; } // enter tb_spinlock_enter(&spider->lock); // done tb_bool_t ok = tb_false; tb_size_t size = 0; tb_demo_spider_task_t* task = tb_null; tb_bool_t repeat = tb_false; do { // check tb_assert_and_check_break(spider->filter && spider->pool); // the task count size = tb_fixed_pool_size(spider->pool); // make the output url if (!tb_demo_spider_make_ourl(spider, iurl, spider->ourl, sizeof(spider->ourl) - 1)) break; // have been done already? if (!tb_bloom_filter_set(spider->filter, spider->ourl)) { // trace tb_trace_d("task: size: %lu, done: %s: repeat", size, iurl); // ok ok = tb_true; repeat = tb_true; break; } // trace tb_trace_d("task: size: %lu, done: %s: ..", size, iurl); // full? tb_check_break(size < TB_DEMO_SPIDER_TASK_MAXN); // make task task = (tb_demo_spider_task_t*)tb_fixed_pool_malloc0(spider->pool); tb_assert_and_check_break(task); // init task task->spider = spider; tb_strlcpy(task->iurl, iurl, sizeof(task->iurl) - 1); tb_strlcpy(task->ourl, spider->ourl, sizeof(task->ourl) - 1); // ok ok = tb_true; } while (0); // leave tb_spinlock_leave(&spider->lock); // ok? if (ok && !repeat) { // done ok = tb_false; do { // check tb_assert_and_check_break(task); // killed? tb_check_break(TB_STATE_OK == tb_atomic_get(&spider->state)); // repeat? if (tb_file_info(task->ourl, tb_null)) { // trace tb_trace_d("task: size: %lu, done: %s: repeat", size, iurl); // ok ok = tb_true; repeat = tb_true; break; } // done task ok = tb_transfer_pool_done(tb_transfer_pool(), task->iurl, task->ourl, 0, spider->limited_rate, tb_demo_spider_task_save, tb_demo_spider_task_ctrl, task); tb_assert_and_check_break(ok); } while (0); } // repeat or failed? if (repeat || !ok) { // exit task if (task) tb_demo_spider_task_exit(task); task = tb_null; // failed? if (!full && !ok) { // trace tb_trace_e("task: size: %lu, done: %s: post failed", size, iurl); } // save full if (full) *full = size < TB_DEMO_SPIDER_TASK_MAXN? tb_false : tb_true; } // ok? return ok; }
static tb_bool_t it_inject(pid_t pid, tb_char_t const* path) { // check tb_assert_and_check_return_val(pid && path, tb_false); // trace tb_trace_d("inject: pid: %lu, path: %s: ..", (tb_size_t)pid, path); #ifdef TB_ARCH_ARM64 // uses libsubstrate first? if (tb_file_info("/usr/lib/libsubstrate.dylib", tb_null)) { // init library tb_bool_t ok = tb_false; tb_handle_t library = tb_dynamic_init("/usr/lib/libsubstrate.dylib"); if (library) { // trace tb_trace_d("library: %p", library); // the func it_MSHookProcess_t pMSHookProcess = tb_dynamic_func(library, "MSHookProcess"); if (pMSHookProcess) { // trace tb_trace_d("MSHookProcess: %p", pMSHookProcess); // hook process ok = pMSHookProcess(pid, path)? tb_true : tb_false; } // exit library tb_dynamic_exit(library); // trace tb_trace_i("%s", ok? "ok" : "no"); // ok? return ok; } } #endif // pid => task task_t task = 0; if (task_for_pid(mach_task_self(), (tb_int_t)pid, &task)) { tb_trace_i("task_for_pid: %lu failed, errno: %d", (tb_size_t)pid, errno); return tb_false; } // trace tb_trace_d("task: %u", task); // stuff cpu_type_t cputype; it_addr_bundle_t addrs; if (!it_stuff(task, &cputype, &addrs)) return tb_false; // trace tb_trace_d("dlopen: %p", addrs.dlopen); tb_trace_d("syscall: %p", addrs.syscall); // alloc stack mach_vm_address_t stack_address = 0; if (mach_vm_allocate(task, &stack_address, it_stack_size, VM_FLAGS_ANYWHERE)) return tb_false; // write path mach_vm_address_t stack_end = stack_address + it_stack_size - 0x100; if (mach_vm_write(task, stack_address, (vm_offset_t)it_address_cast(path), strlen(path) + 1)) return tb_false; /* the first one is the return address * * syscall(SYS_bsdthread_create, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0) */ tb_uint32_t args_32[] = {0, 360, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0}; tb_uint64_t args_64[] = {0, 360, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0}; // init thread state union { it_arm_thread_state_t arm; it_arm_thread_state64_t arm64; it_x86_thread_state32_t x86; it_x86_thread_state64_t x64; natural_t nat; }state; thread_state_flavor_t state_flavor; mach_msg_type_number_t state_count; memset(&state, 0, sizeof(state)); // init thread state for the cpu type switch (cputype) { case CPU_TYPE_ARM: { tb_trace_i("cputype: arm"); memcpy(&state.arm.r[0], args_32 + 1, 4 * sizeof(tb_uint32_t)); if (mach_vm_write(task, stack_end, (vm_offset_t)it_address_cast(args_32 + 5), 2 * sizeof(tb_uint32_t))) return tb_false; state.arm.sp = (tb_uint32_t) stack_end; state.arm.pc = (tb_uint32_t) addrs.syscall; state.arm.lr = (tb_uint32_t) args_32[0]; state_flavor = ARM_THREAD_STATE; state_count = sizeof(state.arm) / sizeof(state.nat); // trace tb_trace_d("init: pc: %x", state.arm.pc); tb_trace_d("init: lr: %x", state.arm.lr); tb_trace_d("init: sp: %x", state.arm.sp); } break; case CPU_TYPE_ARM64: { tb_trace_i("cputype: arm64"); memcpy(&state.arm64.x[0], args_64 + 1, 6 * sizeof(tb_uint64_t)); state.arm64.sp = (tb_uint64_t) stack_end; // state.arm64.fp = (tb_uint64_t) stack_end; state.arm64.pc = (tb_uint64_t) addrs.syscall; state.arm64.lr = (tb_uint64_t) args_64[0]; state_flavor = ARM_THREAD_STATE64; state_count = sizeof(state.arm64) / sizeof(state.nat); // trace tb_trace_d("init: pc: %llx", state.arm64.pc); tb_trace_d("init: lr: %llx", state.arm64.lr); tb_trace_d("init: sp: %llx", state.arm64.sp); } break; case CPU_TYPE_X86: { tb_trace_i("cputype: x86"); if (mach_vm_write(task, stack_end, (vm_offset_t)it_address_cast(args_32), 7 * 4)) return tb_false; state.x86.esp = state.x86.ebp = (tb_uint32_t) stack_end; state.x86.eip = (tb_uint32_t)addrs.syscall; state_flavor = x86_THREAD_STATE32; state_count = sizeof(state.x86) / sizeof(state.nat); } break; case CPU_TYPE_X86_64: { tb_trace_i("cputype: x64"); state.x64.rdi = args_64[1]; state.x64.rsi = args_64[2]; state.x64.rdx = args_64[3]; state.x64.rcx = args_64[4]; state.x64.r8 = args_64[5]; state.x64.r9 = args_64[6]; state.x64.rsp = state.x64.rbp = stack_end; state.x64.rip = addrs.syscall; state_flavor = x86_THREAD_STATE64; state_count = sizeof(state.x64) / sizeof(state.nat); } break; default: tb_trace_i("cputype: unknown: %lx", (tb_size_t)cputype); return tb_false; } // init a remote thread thread_act_t thread = 0; if (thread_create(task, &thread)) return tb_false; // trace tb_trace_d("init: thread: %x", thread); // alloc port mach_port_t exc = 0; mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exc); if (mach_port_insert_right(mach_task_self(), exc, exc, MACH_MSG_TYPE_MAKE_SEND)) return tb_false; // swap port exception_mask_t em[2]; exception_handler_t eh[2]; exception_behavior_t eb[2]; thread_state_flavor_t ef[2]; mach_msg_type_number_t em_count = 2; if (task_swap_exception_ports(task, EXC_MASK_BAD_ACCESS, exc, EXCEPTION_STATE_IDENTITY, state_flavor, em, &em_count, eh, eb, ef)) return tb_false; tb_assert_and_check_return_val(em_count <= 1, tb_false); // resume thread, done: syscall(SYS_bsdthread_create, 0xdeadbeef, 0xdeadbeef, 128 * 1024, 0, 0) if (thread_set_state(thread, state_flavor, &state.nat, state_count)) return tb_false; if (thread_resume(thread)) return tb_false; // we expect three exceptions: one from thread when it returns, one from the new thread when it calls the fake handler, and one from the new thread when it returns from dlopen. tb_bool_t started_dlopen = tb_false; while (1) { // recv msg it_exception_message_t msg; if (mach_msg_overwrite(tb_null, MACH_RCV_MSG, 0, sizeof(msg), exc, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, (tb_pointer_t) &msg, sizeof(msg))) return tb_false; // trace tb_trace_d("recv: msg: from thread: %x", msg.thread.name); // check tb_assert_and_check_return_val((msg.Head.msgh_bits & MACH_MSGH_BITS_COMPLEX), tb_false); tb_assert_and_check_return_val((msg.msgh_body.msgh_descriptor_count != 0), tb_false); tb_assert_and_check_return_val((msg.Head.msgh_size >= offsetof(it_exception_message_t, old_state)), tb_false); tb_assert_and_check_return_val((msg.old_stateCnt == state_count), tb_false); tb_assert_and_check_return_val((msg.Head.msgh_size >= offsetof(it_exception_message_t, old_state) + msg.old_stateCnt * sizeof(natural_t)), tb_false); // the msg state memcpy(&state, msg.old_state, sizeof(state)); // dump // tb_dump_data((tb_byte_t const*)&state, sizeof(state)); // done if (msg.thread.name == thread) { tb_trace_d("terminate"); if (thread_terminate(thread)) return tb_false; } else { // init cond tb_bool_t cond = tb_false; switch(cputype) { case CPU_TYPE_ARM: { // trace tb_trace_d("recv: pc: %x", state.arm.pc); tb_trace_d("recv: lr: %x", state.arm.lr); tb_trace_d("recv: sp: %x", state.arm.sp); // cond cond = ((state.arm.pc & ~1) == 0xdeadbeee)? tb_true : tb_false; } break; case CPU_TYPE_ARM64: { // trace tb_trace_d("recv: pc: %llx", state.arm64.pc); tb_trace_d("recv: lr: %llx", state.arm64.lr); tb_trace_d("recv: sp: %llx", state.arm64.sp); // cond cond = ((state.arm64.pc & ~1) == 0xdeadbeee)? tb_true : tb_false; } break; case CPU_TYPE_X86: cond = (state.x86.eip == 0xdeadbeef)? tb_true : tb_false; break; case CPU_TYPE_X86_64: cond = (state.x64.rip == 0xdeadbeef)? tb_true : tb_false; break; } tb_trace_d("cond: %d, started_dlopen: %d", cond, started_dlopen); if (!cond) { // let the normal crash mechanism handle it task_set_exception_ports(task, em[0], eh[0], eb[0], ef[0]); tb_assert_and_check_return_val(0, tb_false); } else if (started_dlopen) { tb_trace_d("terminate"); if (thread_terminate(msg.thread.name)) return tb_false; break; } else { // done: dlopen(path, RTLD_LAZY) switch(cputype) { case CPU_TYPE_ARM: { state.arm.r[0] = (tb_uint32_t) stack_address; state.arm.r[1] = RTLD_LAZY; state.arm.pc = (tb_uint32_t) addrs.dlopen; state.arm.lr = 0xdeadbeef; } break; case CPU_TYPE_ARM64: { state.arm64.x[0] = (tb_uint64_t) stack_address; state.arm64.x[1] = RTLD_LAZY; state.arm64.pc = (tb_uint64_t) addrs.dlopen; state.arm64.lr = 0xdeadbeef; } break; case CPU_TYPE_X86: { tb_uint32_t stack_stuff[3] = {0xdeadbeef, (tb_uint32_t)stack_address, RTLD_LAZY}; if (mach_vm_write(task, (mach_vm_address_t)state.x86.esp, (vm_offset_t)it_address_cast(&stack_stuff), sizeof(stack_stuff))) return tb_false; } state.x86.eip = (tb_uint32_t) addrs.dlopen; break; case CPU_TYPE_X86_64: { tb_uint64_t stack_stuff = 0xdeadbeef; if (mach_vm_write(task, (mach_vm_address_t)state.x64.rsp, (vm_offset_t)it_address_cast(&stack_stuff), sizeof(stack_stuff))) return tb_false; state.x64.rip = addrs.dlopen; state.x64.rdi = stack_address; state.x64.rsi = RTLD_LAZY; } break; } it_exception_reply_t reply; memcpy(&reply.Head, &msg.Head, sizeof(mach_msg_header_t)); reply.Head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; reply.Head.msgh_size = offsetof(it_exception_reply_t, new_state) + state_count * sizeof(natural_t); reply.Head.msgh_id += 100; memcpy(&reply.NDR, &msg.NDR, sizeof(NDR_record_t)); reply.RetCode = 0; reply.flavor = state_flavor; reply.new_stateCnt = state_count; memcpy(&reply.new_state, &state, sizeof(state)); if (thread_set_state(msg.thread.name, state_flavor, &state.nat, state_count)) return tb_false; if (mach_msg(&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL)) return tb_false; started_dlopen = tb_true; } } } // exit if (stack_address) vm_deallocate(task, stack_address, it_stack_size); if (thread) { thread_terminate(thread); mach_port_deallocate(mach_task_self(), thread); } if (task) mach_port_deallocate(mach_task_self(), task); if (exc) mach_port_deallocate(mach_task_self(), exc); // ok tb_trace_i("ok"); return tb_true; }
// p = process.openv(shellname, argv, outfile, errfile) tb_int_t xm_process_openv(lua_State* lua) { // check tb_assert_and_check_return_val(lua, 0); // check table if (!lua_istable(lua, 2)) { // error lua_pushfstring(lua, "invalid argv type(%s) for process.openv", luaL_typename(lua, 2)); lua_error(lua); return 0; } // get the output and error file tb_char_t const* shellname = lua_tostring(lua, 1); tb_char_t const* outfile = lua_tostring(lua, 3); tb_char_t const* errfile = lua_tostring(lua, 4); tb_check_return_val(shellname, 0); // get the arguments count tb_long_t argn = lua_objlen(lua, 2); tb_check_return_val(argn >= 0, 0); // get arguments tb_size_t argi = 0; tb_char_t const** argv = tb_nalloc0_type(1 + argn + 1, tb_char_t const*); tb_check_return_val(argv, 0); // fill arguments argv[0] = shellname; for (argi = 0; argi < argn; argi++) { // get argv[i] lua_pushinteger(lua, argi + 1); lua_gettable(lua, 2); // is string? if (lua_isstring(lua, -1)) { // pass this argument argv[1 + argi] = lua_tostring(lua, -1); } else { // error lua_pushfstring(lua, "invalid argv[%ld] type(%s) for process.openv", argi, luaL_typename(lua, -1)); lua_error(lua); } // pop it lua_pop(lua, 1); } // init attributes tb_process_attr_t attr = {0}; // redirect stdout? if (outfile) { // redirect stdout to file attr.outfile = outfile; attr.outmode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_APPEND; // remove the outfile first if (tb_file_info(outfile, tb_null)) tb_file_remove(outfile); } // redirect stderr? if (errfile) { // redirect stderr to file attr.errfile = errfile; attr.errmode = TB_FILE_MODE_RW | TB_FILE_MODE_CREAT | TB_FILE_MODE_APPEND; // remove the errfile first if (tb_file_info(errfile, tb_null)) tb_file_remove(errfile); } // init process tb_process_ref_t process = tb_process_init(shellname, argv, &attr); if (process) lua_pushlightuserdata(lua, process); else lua_pushnil(lua); // exit argv if (argv) tb_free(argv); argv = tb_null; // ok return 1; }