this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

More progress on debugging support

+262 -37
+5 -1
src/kernel/emulation/linux/CMakeLists.txt
··· 5 5 cmake_policy(SET CMP0005 NEW) 6 6 enable_language(ASM) 7 7 8 - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fvisibility=hidden -fPIC -fno-builtin -ggdb -Wno-int-conversion") 8 + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -fvisibility=hidden -fPIC -fno-builtin -ggdb -Wno-int-conversion -Wno-compare-distinct-pointer-types") 9 9 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -nostdlib") 10 10 11 11 add_definitions(-DBSDTHREAD_WRAP_LINUX_PTHREAD ··· 19 19 # include src/startup for rtsig.h 20 20 include_directories(${CMAKE_CURRENT_SOURCE_DIR} 21 21 ${CMAKE_BINARY_DIR}/src/startup 22 + ${CMAKE_CURRENT_BINARY_DIR} 22 23 ) 23 24 25 + mig(signal/mach_exc.defs) 26 + 24 27 set(emulation_sources 28 + ${CMAKE_CURRENT_BINARY_DIR}/signal/mach_excUser.c 25 29 elfcalls_wrapper.c 26 30 base.c 27 31 syscalls.c
+70 -25
src/kernel/emulation/linux/misc/ptrace.c
··· 8 8 #include <sys/signal.h> 9 9 #include "../signal/kill.h" 10 10 #include "../signal/duct_signals.h" 11 + #include "../signal/sigexc.h" 12 + #include "../process/wait4.h" 13 + #include "../mach/lkm.h" 14 + #include "../../../../lkm/api.h" 11 15 12 16 #define LINUX_PTRACE_TRACEME 0 13 17 #define LINUX_PTRACE_ATTACH 16 14 18 #define LINUX_PTRACE_DETACH 17 15 19 #define LINUX_PTRACE_CONT 7 20 + #define LINUX_PTRACE_KILL 8 16 21 17 22 long sys_ptrace(int request, int pid, void* addr, int data) 18 23 { 19 24 const char* cmd = NULL; 25 + int ret; 20 26 21 27 switch (request) 22 28 { 23 29 case PT_PTRACE_ME: 24 30 { 25 - int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_TRACEME, pid, addr, data); 31 + ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_TRACEME, pid, addr, data); 26 32 27 33 if (ret < 0) 28 34 ret = errno_linux_to_bsd(ret); 29 35 30 - return ret; 31 - //cmd = "PT_PTRACE_ME"; break; 36 + //return ret; 37 + cmd = "PT_PTRACE_ME"; break; 32 38 } 33 39 case PT_KILL: 34 - return sys_kill(pid, SIGKILL, 1); 35 - // cmd = "PT_KILL"; break; 36 - case PT_ATTACH: // PT_ATTACH 37 - case PT_ATTACHEXC: // PT_ATTACHEXC 38 40 { 39 - //do_attach: 40 - int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_ATTACH, pid, addr, data); 41 + //return sys_kill(pid, SIGKILL, 1); 42 + ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_KILL, pid, addr, data); 43 + if (ret < 0) 44 + ret = errno_linux_to_bsd(ret); 45 + 46 + // return ret; 47 + cmd = "PT_KILL"; break; 48 + } 49 + case PT_ATTACHEXC: 50 + // This triggers darling_sigexc_self() in the remote process. 51 + linux_sigqueue(pid, SIGNAL_SIGEXC_TOGGLE, SIGRT_MAGIC_ENABLE_SIGEXC); 52 + 53 + // fall through to PT_ATTACH 54 + case PT_ATTACH: 55 + { 56 + ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_ATTACH, pid, addr, data); 41 57 42 58 if (ret < 0) 59 + { 43 60 ret = errno_linux_to_bsd(ret); 61 + } 62 + else 63 + { 64 + // Call wait4 to process the SIGSTOP that is sent by kernel on PTRACE_ATTACH 65 + // and make sure it is passed to the tracee (to get it sent back to us as a Mach message). 66 + sys_wait4(pid, NULL, DARLING_WAIT_NORESTART | BSD_WSTOPPED, NULL); 67 + } 44 68 45 - return ret; 46 - // cmd = "PT_ATTACH"; break; 69 + //return ret; 70 + cmd = "PT_ATTACH"; break; 47 71 } 48 72 case PT_DETACH: 49 73 { 50 - int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_DETACH, pid, addr, data); 74 + // Tell the tracee to restore original application signal handlers. 75 + linux_sigqueue(pid, SIGNAL_SIGEXC_TOGGLE, SIGRT_MAGIC_DISABLE_SIGEXC); 76 + 77 + ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_DETACH, pid, addr, data); 51 78 52 79 if (ret < 0) 53 80 ret = errno_linux_to_bsd(ret); 54 81 55 - return ret; 56 - // cmd = "PT_DETACH"; break; 82 + //return ret; 83 + cmd = "PT_DETACH"; break; 57 84 } 58 85 case PT_SIGEXC: 86 + { 87 + darling_sigexc_self(); 88 + ret = 0; 89 + 90 + // return ret; 59 91 cmd = "PT_SIGEXC"; break; 92 + } 60 93 case PT_CONTINUE: 61 - // case PT_THUPDATE: 62 94 { 63 95 int signal = 0; 64 96 if (data != -1) 65 97 signal = signum_bsd_to_linux(data); 66 - int ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_CONT, pid, NULL, signal); 98 + ret = LINUX_SYSCALL(__NR_ptrace, LINUX_PTRACE_CONT, pid, NULL, signal); 67 99 68 100 if (ret < 0) 69 101 ret = errno_linux_to_bsd(ret); 70 102 71 - return ret; 72 - // cmd = "PT_THUPDATE"; break; 103 + // return ret; 104 + cmd = "PT_CONTINUE"; break; 105 + } 106 + case PT_THUPDATE: 107 + { 108 + // Convert thread_t to process ID 109 + int tid = lkm_call(NR_tid_for_thread, addr); 110 + if (tid < 0) 111 + return -ESRCH; 112 + 113 + int signal = 0; 114 + if (data != -1) 115 + signal = signum_bsd_to_linux(data); 116 + 117 + ret = linux_sigqueue_thread(pid, tid, SIGNAL_SIGEXC_THUPDATE, signal); 118 + if (ret < 0) 119 + ret = errno_linux_to_bsd(ret); 120 + 121 + // return ret; 122 + cmd = "PT_THUPDATE"; break; 73 123 } 74 - //case 14: 75 - //{ 76 - // goto do_attach; 77 - // cmd = "PT_ATTACHEXC"; break; 78 - //} 79 124 } 80 125 81 126 if (cmd != NULL) 82 - __simple_printf("ptrace() req=%s\n", cmd); 127 + __simple_printf("ptrace() req=%s, ret=%d\n", cmd, ret); 83 128 else 84 129 __simple_printf("ptrace() req=%d\n", request); 85 130 86 - return -ENOSYS; 131 + return ret; 87 132 } 88 133
+11 -2
src/kernel/emulation/linux/process/wait4.c
··· 2 2 #include "../base.h" 3 3 #include "../errno.h" 4 4 #include "../signal/duct_signals.h" 5 + #include "../signal/sigexc.h" 5 6 #include "../misc/ptrace.h" 6 7 #include "../mach/lkm.h" 7 8 #include "../../../../lkm/api.h" 8 9 #include <sys/signal.h> 9 10 #include <stddef.h> 10 11 #include <linux-syscalls/linux.h> 12 + 13 + extern int getpid(void); 11 14 12 15 long sys_wait4(int pid, int* status, int options, void* rusage) 13 16 { ··· 46 49 // We are ptracing the target process. 47 50 // Allow the execution to continue so that the ptraced process can translate 48 51 // the signal into a Mach message. 52 + 49 53 if (signal == SIGSTOP) 50 54 { 51 - // TODO: notify target process it has been SIGSTOP'ed via sigqueue 55 + // Notify target process it has been SIGSTOP'ed via sigqueue 56 + // because we're just about to resume it and we need it 57 + // to pass the signal back to us through a Mach message. 58 + linux_sigqueue(ret, SIGNAL_SIGEXC_THUPDATE, -SIGSTOP); 52 59 } 53 60 54 61 sys_ptrace(PT_CONTINUE, ret, NULL, signal); 55 - goto restart; 62 + 63 + if (!(options & DARLING_WAIT_NORESTART)) 64 + goto restart; 56 65 } 57 66 } 58 67
+2
src/kernel/emulation/linux/process/wait4.h
··· 19 19 #define BSD_WCONTINUED 0x10 20 20 #define BSD_WNOWAIT 0x20 21 21 22 + #define DARLING_WAIT_NORESTART 0x20000 23 + 22 24 #endif 23 25
-2
src/kernel/emulation/linux/signal/duct_signals.c
··· 1 - #define __sigset_t_defined 2 - #include "../../../../../platform-include/sys/signal.h" 3 1 #include "duct_signals.h" 4 2 5 3 int signum_linux_to_bsd(int signum)
+2
src/kernel/emulation/linux/signal/duct_signals.h
··· 1 1 #ifndef LINUX_DUCT_SIGNALS_H 2 2 #define LINUX_DUCT_SIGNALS_H 3 + #define __sigset_t_defined 4 + #include <sys/signal.h> 3 5 4 6 #define LINUX_NSIG 32 5 7 #define LINUX_SIGHUP 1
+1
src/kernel/emulation/linux/signal/mach_exc.defs
··· 1 + ../../../../../platform-include/mach/mach_exc.defs
+2
src/kernel/emulation/linux/signal/sigaction.h
··· 3 3 #include "duct_signals.h" 4 4 #include "sigaltstack.h" 5 5 6 + #undef sa_sigaction 7 + 6 8 #define BSD_SA_ONSTACK 0x0001 7 9 #define BSD_SA_RESTART 0x0002 8 10 #define BSD_SA_RESETHAND 0x0004
+163 -6
src/kernel/emulation/linux/signal/sigexc.c
··· 1 1 #include "sigexc.h" 2 2 #include "../base.h" 3 + #include "../unistd/exit.h" 3 4 #include <stddef.h> 5 + #include <sys/signal.h> 4 6 #include <linux-syscalls/linux.h> 7 + #include <pthread/tsd_private.h> 8 + #include "signal/mach_exc.h" 5 9 6 10 // Support for Darwin debugging. 7 11 // Unlike other Unix-like systems, macOS doesn't use wait() to handle events in the debugged process. 12 + // wait() only receives termination events. 8 13 9 - static bool am_i_ptraced = false; 14 + static volatile bool am_i_ptraced = false; 10 15 static void handle_rt_signal(int signum); 11 16 extern void sig_restorer(void); 17 + extern int getpid(void); 18 + 12 19 void darling_sigexc_uninstall(void); 13 20 void sigrt_handler(int signum, struct linux_siginfo* info, void* ctxt); 21 + 22 + #define SIGEXC_TSD_KEY 102 14 23 15 24 void sigexc_setup(void) 16 25 { ··· 54 63 } 55 64 else if (signum == SIGNAL_SIGEXC_THUPDATE) 56 65 { 57 - // TODO: Change how a pending signal is handled 58 - // Use TLS? 59 66 if (!am_i_ptraced) 60 67 return; 68 + 69 + // Examine info->si_value 70 + // If 0, drop the signal 71 + // If >0, process the signal 72 + // If <0, introduce a new signal 73 + int sig = info->si_value; 74 + if (sig < 0) 75 + { 76 + // This is only used to pass a SIGSTOP to the traced process (from the debugger) 77 + // and have it passed back through the sigexc mechanism. 78 + // See sys_wait4(). 79 + sigexc_handler(-sig, NULL, NULL); 80 + } 81 + else 82 + { 83 + // This is the debugger telling us how to deal with the signal. 84 + _pthread_setspecific_direct(SIGEXC_TSD_KEY, sig); 85 + } 61 86 } 62 87 } 63 88 ··· 68 93 { 69 94 struct linux_sigaction sa; 70 95 sa.sa_sigaction = sigrt_handler; 71 - sa.sa_mask = sig_masks[i]; 96 + sa.sa_mask = 0xffffffff; // all other standard Unix signals should be blocked while the handler is run 72 97 sa.sa_flags = LINUX_SA_RESTORER | LINUX_SA_SIGINFO | LINUX_SA_RESTART; 73 98 sa.sa_restorer = sig_restorer; 74 99 ··· 101 126 } 102 127 } 103 128 129 + static mach_port_t get_exc_port(int type) 130 + { 131 + mach_msg_type_number_t count = 0; 132 + exception_mask_t masks[EXC_TYPES_COUNT]; 133 + mach_port_t ports[EXC_TYPES_COUNT]; 134 + exception_behavior_t behaviors[EXC_TYPES_COUNT]; 135 + thread_state_flavor_t flavors[EXC_TYPES_COUNT]; 136 + 137 + kern_return_t result = task_get_exception_ports(mach_task_self(), 1 << type, 138 + masks, &count, ports, behaviors, flavors); 139 + 140 + if (result == KERN_SUCCESS) 141 + return ports[type]; 142 + 143 + return 0; 144 + } 145 + 104 146 void sigexc_handler(int linux_signum, struct linux_siginfo* info, void* ctxt) 105 147 { 148 + if (!darling_am_i_ptraced()) 149 + return; 150 + 151 + // Send a Mach message to the debugger. 152 + // The debugger may use ptrace(PT_THUPDATE) to change how the signal is processed. 153 + 154 + int mach_exception; 155 + long long codes[EXCEPTION_CODE_MAX] = { 0 }; 156 + mach_port_t port; 157 + 158 + int bsd_signum = signum_linux_to_bsd(linux_signum); 159 + if (bsd_signum <= 0) 160 + return; 161 + 106 162 // SIGSEGV + SIGBUS -> EXC_BAD_ACCESS 107 163 // SIGTRAP -> EXC_BREAKPOINT 108 - // * -> EXC_SOFTWARE with EXC_SOFT_SIGNAL (e.g. SIGSTOP 109 - if (darling_am_i_ptraced()) 164 + // SIGILL -> EXC_BAD_INSTRUCTION 165 + // SIGFPE -> EXC_ARITHMETIC 166 + // * -> EXC_SOFTWARE with EXC_SOFT_SIGNAL (e.g. SIGSTOP) 167 + 168 + switch (bsd_signum) 169 + { 170 + case SIGSEGV: 171 + mach_exception = EXC_BAD_ACCESS; 172 + codes[0] = EXC_I386_GPFLT; 173 + break; 174 + case SIGBUS: 175 + mach_exception = EXC_BAD_ACCESS; 176 + codes[0] = EXC_I386_ALIGNFLT; 177 + break; 178 + case SIGTRAP: 179 + mach_exception = EXC_BREAKPOINT; 180 + codes[0] = EXC_I386_BPT; 181 + break; 182 + case SIGILL: 183 + mach_exception = EXC_BAD_INSTRUCTION; 184 + codes[0] = EXC_I386_INVOP; 185 + break; 186 + case SIGFPE: 187 + mach_exception = EXC_ARITHMETIC; 188 + codes[0] = info->si_code; 189 + break; 190 + default: 191 + mach_exception = EXC_SOFTWARE; 192 + codes[0] = EXC_SOFT_SIGNAL; 193 + codes[1] = bsd_signum; 194 + } 195 + 196 + port = get_exc_port(mach_exception); 197 + 198 + if (port != 0) 110 199 { 200 + _pthread_setspecific_direct(SIGEXC_TSD_KEY, bsd_signum); 201 + 202 + mach_exception_raise(port, mach_thread_self(), mach_task_self(), mach_exception, codes, sizeof(codes) / sizeof(codes[0])); 203 + 204 + bsd_signum = _pthread_getspecific_direct(SIGEXC_TSD_KEY); 111 205 } 206 + 207 + // Pass the signal to the application handler or emulate the effects of the signal if SIG_DFL is set. 208 + if (bsd_signum) 209 + { 210 + bsd_sig_handler* handler = sig_handlers[bsd_signum]; 211 + if (handler == SIG_DFL || handler == SIG_ERR) 212 + { 213 + switch (bsd_signum) 214 + { 215 + // We have to stop the process manually 216 + case SIGSTOP: 217 + case SIGTSTP: 218 + task_suspend(mach_task_self()); 219 + break; 220 + 221 + // These signals do nothing by default 222 + case SIGCHLD: 223 + case SIGWINCH: 224 + case SIGURG: 225 + break; 226 + 227 + // Other signals cause termination or core dump. 228 + default: 229 + { 230 + int linux_signum = signum_bsd_to_linux(bsd_signum); 231 + sys_exit(linux_signum); 232 + } 233 + } 234 + } 235 + else if (handler != SIG_IGN) 236 + { 237 + handler_linux_to_bsd(signum_bsd_to_linux(bsd_signum), info, ctxt); 238 + } 239 + } 240 + } 241 + 242 + #define LINUX_SI_QUEUE (-1) 243 + int linux_sigqueue(int pid, int rtsig, int value) 244 + { 245 + struct linux_siginfo si; 246 + 247 + memset(&si, 0, sizeof(si)); 248 + si.si_signo = rtsig; 249 + si.si_code = LINUX_SI_QUEUE; 250 + si.si_pid = getpid(); 251 + si.si_uid = LINUX_SYSCALL(__NR_getuid); 252 + si.si_value = value; 253 + 254 + return LINUX_SYSCALL(__NR_rt_sigqueueinfo, pid, rtsig, &si); 255 + } 256 + 257 + int linux_sigqueue_thread(int pid, int tid, int rtsig, int value) 258 + { 259 + struct linux_siginfo si; 260 + 261 + memset(&si, 0, sizeof(si)); 262 + si.si_signo = rtsig; 263 + si.si_code = LINUX_SI_QUEUE; 264 + si.si_pid = getpid(); 265 + si.si_uid = LINUX_SYSCALL(__NR_getuid); 266 + si.si_value = value; 267 + 268 + return LINUX_SYSCALL(__NR_rt_tgsigqueueinfo, pid, tid, rtsig, &si); 112 269 } 113 270
+6 -1
src/kernel/emulation/linux/signal/sigexc.h
··· 4 4 #include "rtsig.h" 5 5 #include "sigaction.h" 6 6 7 + // Uses one of the below magic values to toggle the debugging state 7 8 #define SIGNAL_SIGEXC_TOGGLE LINUX_SIGRTMIN 9 + 10 + // A BSD signal number is passed as value 8 11 #define SIGNAL_SIGEXC_THUPDATE (LINUX_SIGRTMIN + 1) 9 12 10 13 #define SIGRT_MAGIC_ENABLE_SIGEXC 0xdebdeb01 11 14 #define SIGRT_MAGIC_DISABLE_SIGEXC 0xdebdeb00 12 - #define SIGRT_ 13 15 14 16 // Initializes this module 15 17 void sigexc_setup(void); ··· 20 22 // for PT_SIGEXC to handle this operation synchronously 21 23 void darling_sigexc_self(void); 22 24 void sigexc_handler(int linux_signum, struct linux_siginfo* info, void* ctxt); 25 + 26 + int linux_sigqueue(int pid, int rtsig, int value); 27 + int linux_sigqueue_thread(int pid, int tid, int rtsig, int value); 23 28 24 29 #endif 25 30