duct-tape.h
1 #ifndef _DARLINGSERVER_DUCT_TAPE_H_ 2 #define _DARLINGSERVER_DUCT_TAPE_H_ 3 4 #include <stdint.h> 5 #include <stddef.h> 6 #include <stdbool.h> 7 8 #include <libsimple/lock.h> 9 #include <darlingserver/rpc.internal.h> 10 #include <darlingserver/rpc-supplement.h> 11 #include <darlingserver/rpc.h> 12 13 #include <darlingserver/duct-tape/types.h> 14 #include <darlingserver/duct-tape/hooks.h> 15 16 #ifdef __cplusplus 17 extern "C" { 18 #endif 19 20 void dtape_init(const dtape_hooks_t* hooks); 21 void dtape_init_in_thread(void); 22 void dtape_deinit(void); 23 24 uint32_t dtape_task_self_trap(void); 25 uint32_t dtape_host_self_trap(void); 26 uint32_t dtape_thread_self_trap(void); 27 uint32_t dtape_mach_reply_port(void); 28 uint32_t dtape_thread_get_special_reply_port(void); 29 uint32_t dtape_mk_timer_create(void); 30 31 DSERVER_DTAPE_DECLS; 32 33 typedef void (*dtape_kqchan_mach_port_notification_callback_f)(void* context); 34 35 /** 36 * The threshold beyond which thread IDs are considered IDs for kernel threads. 37 * Thread IDs lower than this value are reserved for userspace threads. 38 * Thread IDs greater than or equal to this value are reserved for kernelspace threads. 39 * 40 * This should NOT be used to differentiate kernelspace threads from userspace ones. 41 * This is simply used as a convenient cutoff beyond which we do not expect Linux to actually assign 42 * thread IDs within our namespace. In practice, there should be no difference between the way userspace 43 * and kernelspace threads are handled in the duct-tape code. 44 * 45 * This is used as the starting offset for thread IDs for kernelspace threads (which do not have a "real" managed Darling thread backing them). 46 */ 47 #define DTAPE_KERNEL_THREAD_ID_THRESHOLD (1ULL << 22) 48 49 /** 50 * Creates a new duct-tape task. The caller receives a reference on the new task. 51 * 52 * An @p nsid value of `0` indicates the task being created is the kernel task. 53 */ 54 dtape_task_t* dtape_task_create(dtape_task_t* parent_task, uint32_t nsid, void* context, dserver_rpc_architecture_t architecture); 55 dtape_thread_t* dtape_thread_create(dtape_task_t* task, uint64_t nsid, void* context); 56 dtape_kqchan_mach_port_t* dtape_kqchan_mach_port_create(dtape_task_t* owning_task, uint32_t port, uint64_t receive_buffer, uint64_t receive_buffer_size, uint64_t saved_filter_flags, dtape_kqchan_mach_port_notification_callback_f notification_callback, void* context); 57 dtape_semaphore_t* dtape_semaphore_create(dtape_task_t* owning_task, int initial_value); 58 59 void dtape_kqchan_mach_port_destroy(dtape_kqchan_mach_port_t* kqchan); 60 void dtape_semaphore_destroy(dtape_semaphore_t* semaphore); 61 62 void dtape_thread_entering(dtape_thread_t* thread); 63 void dtape_thread_exiting(dtape_thread_t* thread); 64 void dtape_thread_set_handles(dtape_thread_t* thread, uintptr_t pthread_handle, uintptr_t dispatch_qaddr); 65 /** 66 * Returns the thread corresponding to the given thread port. 67 * 68 * @warning It is VERY important that the caller ensures the thread cannot die while we're looking it up. 69 * This can be accomplished, for example, by locking the global thread list before the call. 70 */ 71 dtape_thread_t* dtape_thread_for_port(uint32_t thread_port); 72 void* dtape_thread_context(dtape_thread_t* thread); 73 int dtape_thread_load_state_from_user(dtape_thread_t* thread, uintptr_t thread_state_address, uintptr_t float_state_address); 74 int dtape_thread_save_state_to_user(dtape_thread_t* thread, uintptr_t thread_state_address, uintptr_t float_state_address); 75 void dtape_thread_process_signal(dtape_thread_t* thread, int bsd_signal_number, int linux_signal_number, int code, uintptr_t signal_address); 76 void dtape_thread_wait_while_user_suspended(dtape_thread_t* thread); 77 void dtape_thread_retain(dtape_thread_t* thread); 78 void dtape_thread_release(dtape_thread_t* thread); 79 void dtape_thread_sigexc_enter(dtape_thread_t* thread); 80 void dtape_thread_sigexc_exit(dtape_thread_t* thread); 81 void dtape_thread_sigexc_enter2(dtape_thread_t* thread); 82 void dtape_thread_dying(dtape_thread_t* thread); 83 84 void dtape_task_uidgid(dtape_task_t* task, int new_uid, int new_gid, int* old_uid, int* old_gid); 85 void dtape_task_retain(dtape_task_t* task); 86 void dtape_task_release(dtape_task_t* task); 87 void dtape_task_dying(dtape_task_t* task); 88 void dtape_task_set_dyld_info(dtape_task_t* task, uint64_t address, uint64_t length); 89 void dtape_task_set_sigexc_enabled(dtape_task_t* task, bool enabled); 90 bool dtape_task_try_resume(dtape_task_t* task); 91 92 /** 93 * Invoked when a timer armed by an earlier call to the timer_arm hook expires. 94 * 95 * It is allowed to be invoked spuriously. 96 */ 97 void dtape_timer_fired(void); 98 99 void dtape_kqchan_mach_port_modify(dtape_kqchan_mach_port_t* kqchan, uint64_t receive_buffer, uint64_t receive_buffer_size, uint64_t saved_filter_flags); 100 void dtape_kqchan_mach_port_disable_notifications(dtape_kqchan_mach_port_t* kqchan); 101 bool dtape_kqchan_mach_port_fill(dtape_kqchan_mach_port_t* kqchan, dserver_kqchan_reply_mach_port_read_t* reply, uint64_t default_buffer, uint64_t default_buffer_size); 102 bool dtape_kqchan_mach_port_has_events(dtape_kqchan_mach_port_t* kqchan); 103 104 void dtape_semaphore_up(dtape_semaphore_t* semaphore); 105 dtape_semaphore_wait_result_t dtape_semaphore_down(dtape_semaphore_t* semaphore); 106 bool dtape_semaphore_down_simple(dtape_semaphore_t* semaphore); 107 108 uint64_t dtape_debug_task_port_count(dtape_task_t* task); 109 uint64_t dtape_debug_task_list_ports(dtape_task_t* task, dtape_debug_task_list_ports_iterator_f iterator, void* context); 110 uint64_t dtape_debug_portset_list_members(dtape_task_t* task, uint32_t portset, dtape_debug_portset_list_members_iterator_f iterator, void* context); 111 uint64_t dtape_debug_port_list_messages(dtape_task_t* task, uint32_t port, dtape_debug_port_list_messages_iterator_f iterator, void* context); 112 113 #ifdef __cplusplus 114 }; 115 #endif 116 117 #endif // _DARLINGSERVER_DUCT_TAPE_H_