sig.c (10170B)
1 #include <sys/signal.h> 2 #include <ucontext.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <assert.h> 6 #include <string.h> 7 #include <signal.h> 8 9 #include "vx32.h" 10 #include "vx32impl.h" 11 12 static void sighandler(int signo, siginfo_t *si, void *ucontext) 13 { 14 if (vx32_sighandler(signo, si, ucontext)){ 15 // Back into the fire. 16 return; 17 } 18 19 // vx32_sighandler thought that vx32 wasn't 20 // running or otherwise didn't know what to do. 21 // TODO: If there was a handler registered before us, call it? 22 // If the signal is not important, ignore it. 23 if (signo == SIGVTALRM || signo == SIGALRM) 24 return; 25 26 // Otherwise, deregister the handler and let the signal 27 // happen again -- this time we'll crash and get a core dump. 28 vxprint("Unregistering signal handler %d\n", signo); 29 signal(signo, SIG_DFL); 30 } 31 32 // vx32_sighandler saves execution context, finds emu, 33 // and calls vxemu_sighandler. If we're here, the fs segment 34 // register pointed at a valid emu, but we still might not have 35 // been executing actual vx32 translations. 36 // Trapeip is 0xffffffff if the other segment registers 37 // suggest we weren't inside vxrun_setup ... vxrun_cleanup. 38 int vxemu_sighandler(vxemu *emu, uint32_t trapeip) 39 { 40 if (vx32_debugxlate) 41 vxprint("vxemu_sighandler %p %#x\n", emu, trapeip); 42 43 if (emu->cpu_trap == 0) 44 return VXSIG_ERROR; 45 46 // Not in vx32 code: assume registers saved already and trap. 47 if (trapeip == 0xffffffff) 48 return VXSIG_TRAP; 49 50 if (emu->ininst) { 51 // In the middle of translating an instruction, 52 // so the registers are already saved. 53 // The signal hander knows the exact fault address, 54 // which may be a bit after emu->ininst. 55 // In fact, the fault address may be one or two 56 // instructions past emu->cpu.eip, and a real 57 // processor would not throw the trap until it 58 // actually got to the unreadable instruction, 59 // but there's not really any harm in trapping now instead. 60 return VXSIG_TRAP; 61 } 62 63 // Single-stepping? Use the original trap code. 64 if (emu->cpu_trap == VXTRAP_SINGLESTEP && emu->saved_trap){ 65 emu->cpu_trap = emu->saved_trap; 66 emu->saved_trap = 0; 67 } 68 69 // In vx32 runtime code (rts.S, run32/64.S), the registers are in flux. 70 // Single-step until we can get out; then they'll be safe to look at. 71 // This only makes sense if the trap is an external trap like a timer. 72 char *eip = (char*)(uintptr_t)trapeip; 73 if ((emu->cpu_trap&VXTRAP_CATEGORY) != VXTRAP_CPU){ 74 // The check for run32/64.S doesn't look for the entire file. 75 // Instead it looks for anywhere in the file except 76 // vxrun_cleanup. If we single-step out of vxrun_cleanup, 77 // then vx32_sighandler will get a single-step trap when 78 // the vx32 segment register doesn't point at emu and 79 // won't know what to do. If we're in vxrun_cleanup, then 80 // all the cpu registers are known to be saved. 81 extern char vx_rts_S_start[], vx_rts_S_end[]; 82 extern char vx_run_S_start[]; 83 if ((vx_rts_S_start <= eip && eip < vx_rts_S_end) 84 || (vx_run_S_start <= eip && eip < (char*)vxrun_cleanup)){ 85 SingleStep: 86 if(++emu->nsinglestep > 500){ 87 // Give up: something is wrong. 88 vxprint("vx32: single-stepping but stuck\n"); 89 return VXSIG_ERROR; 90 } 91 emu->saved_trap = emu->cpu_trap; 92 emu->cpu_trap = 0; 93 return VXSIG_SINGLESTEP; 94 } 95 } 96 emu->nsinglestep = 0; 97 98 // In translated code buffer? Find original eip. 99 if ((char*)emu->codebuf <= eip && eip < (char*)emu->codefree){ 100 // Binary search for the translated chunk in which the trap occurred. 101 // NB: frags appear in the opposite order as the code itself. 102 uint32_t *codetab = emu->codetab; 103 unsigned lofrag = 0; 104 unsigned hifrag = (uint32_t*)emu->codetop - codetab - 1; 105 while (hifrag > lofrag) { 106 unsigned midfrag = (lofrag + hifrag) / 2; 107 uint32_t mideip = codetab[midfrag]; 108 if (trapeip >= mideip) 109 hifrag = midfrag; 110 else 111 lofrag = midfrag + 1; 112 } 113 struct vxfrag *frag = (vxfrag*)(intptr_t)codetab[lofrag]; 114 115 // The eip is known to be in the translation buffer, 116 // but the buffer contains both fragment headers and 117 // fragment code. Make sure it's not in a fragment header. 118 if (trapeip < (uint32_t)(intptr_t)FRAGCODE(frag)) 119 return VXSIG_ERROR; 120 unsigned ofs = trapeip - (uint32_t)(intptr_t)FRAGCODE(frag); 121 122 // The very first instruction in each fragment is the one that 123 // restores ebx. It is not included in the table, because it 124 // doesn't correspond to any original source instruction. 125 // If we're there, pretend we're at the first instruction in the 126 // fragment but don't save ebx -- it's already saved. 127 if (ofs < frag->insn[0].dstofs) { 128 emu->cpu.eip = frag->eip + frag->insn[0].srcofs; 129 return VXSIG_TRAP | (VXSIG_SAVE_ALL & ~VXSIG_SAVE_EBX); 130 } 131 132 // Binary search through this fragment's instruction table 133 // for the actual faulting translated instruction, 134 // and compute the corresponding EIP in the original vx32 code. 135 unsigned ninsn = frag->ninsn; 136 unsigned loinsn = 0; 137 unsigned hiinsn = ninsn - 1; 138 while (hiinsn > loinsn) { 139 unsigned midinsn = (loinsn + hiinsn + 1) / 2; 140 unsigned midofs = frag->insn[midinsn].dstofs; 141 if (ofs >= midofs) 142 loinsn = midinsn; 143 else 144 hiinsn = midinsn - 1; 145 } 146 struct vxinsn *insn = &frag->insn[loinsn]; 147 148 if (ofs < insn->dstofs) { 149 // How did that happen? 150 // We checked for ofs < frag->insn[0].dstofs above. 151 assert(0); 152 } 153 emu->cpu.eip = frag->eip + insn->srcofs; 154 155 // At the beginning of a translated instruction (before the 156 // translation has begun to execute) all registers are valid. 157 if (ofs == insn->dstofs) 158 return VXSIG_TRAP | VXSIG_SAVE_ALL; 159 160 // But some translations end up being more than one instruction, 161 // and we have to handle those specially, if they've executed 162 // only some of the instructions. 163 int r; 164 switch (insn->itype) { 165 default: 166 assert(0); 167 168 case VXI_JUMP: 169 case VXI_ENDFRAG: 170 // Direct jumps don't trash any registers while 171 // making their way into vxrun_lookup_backpatch. 172 return VXSIG_TRAP | VXSIG_SAVE_ALL; 173 174 case VXI_CALL: 175 // Call pushes a return address onto the stack 176 // as the first instruction of the translation. 177 // We can't just pop it back off, because we would 178 // still need to restore the value that got overwritten. 179 // The target eip is stored in the word at byte 26 in 180 // the translation. 181 // Call does not trash any registers on the way 182 // into vxrun_lookup_backpatch. 183 emu->cpu.eip = *(uint32_t*)(FRAGCODE(frag)+insn->dstofs+26); 184 return VXSIG_TRAP | VXSIG_SAVE_ALL; 185 186 case VXI_JUMPIND: 187 // Indirect jumps save ebx as their first instruction, 188 // and then they trash it. Since we're not at the first 189 // instruction (see above), it might or might not be 190 // trashed but is definitely already saved. 191 return VXSIG_TRAP | (VXSIG_SAVE_ALL & ~VXSIG_SAVE_EBX); 192 193 case VXI_CALLIND: 194 // Indirect call is like indirect jump except that it 195 // pushes a return address onto the stack in the 196 // instruction that ends at dstlen-5. Until that point, 197 // only ebx has been trashed (but saved) and the stack 198 // is unmodified. At that point, though, the stack is now 199 // modified and we must commit the instruction: 200 // ebx contains the target eip. 201 r = VXSIG_TRAP | (VXSIG_SAVE_ALL & ~VXSIG_SAVE_EBX); 202 if (ofs >= insn->dstofs + insn->dstlen - 5) 203 r |= VXSIG_SAVE_EBX_AS_EIP; 204 return r; 205 206 case VXI_RETURN: 207 case VXI_RETURN_IMM:; 208 // Return is like indirect jump, but we have to treat it 209 // as committed once the pop ebx happens. 210 // Pop ebx happens at byte 7 of the translation. 211 r = VXSIG_TRAP | (VXSIG_SAVE_ALL & ~VXSIG_SAVE_EBX); 212 if (ofs - insn->dstofs > 7) { 213 r |= VXSIG_SAVE_EBX_AS_EIP; 214 215 if (insn->itype == VXI_RETURN_IMM) { 216 // Return immediate is like return but if we've committed 217 // to popping ebx we also have to commit to popping 218 // the immediate number of bytes off the stack. 219 // The immediate is a 32-bit word at byte 10 of 220 // the translation, but it was originally only 16 bits 221 // in the original return instruction, so it's okay to 222 // truncate. 223 r |= VXSIG_ADD_COUNT_TO_ESP; 224 r |= *(uint16_t*)(FRAGCODE(frag)+insn->dstofs+10) << VXSIG_COUNT_SHIFT; 225 } 226 } 227 return r; 228 229 case VXI_TRAP: 230 // Traps save eax as their first instruction and then 231 // they trash it. Since we're not at the first instruction 232 // (see above), it might or might not be trashed but 233 // is definitely already saved. 234 return VXSIG_TRAP | (VXSIG_SAVE_ALL & ~VXSIG_SAVE_EAX); 235 236 case VXI_LOOP: 237 case VXI_LOOPZ: 238 case VXI_LOOPNZ: 239 // The first instruction in the loop translation decrements ecx. 240 // The rest figure out whether to jump. 241 // We can back out by re-incrementing ecx. 242 // Untested (most loops translate into actual loop instructions). 243 return VXSIG_TRAP | VXSIG_SAVE_ALL | VXSIG_INC_ECX; 244 } 245 } 246 247 // Let's see. 248 // The fs segment register pointed at a vxemu, so we're in vxproc_run. 249 // The eip is not in rts.S, nor in run32/64.S. 250 // The eip is not in a fragment translation. 251 // We're not translating an instruction (emu->ininst == nil). 252 // That pretty much means we're in some interstitial instruction. 253 // Assume the registers are already saved. 254 return VXSIG_TRAP; 255 } 256 257 int vx32_siginit(void) 258 { 259 stack_t ss; 260 void *stk; 261 struct sigaction sa; 262 263 // See if there's already an alternate signal stack. 264 if (sigaltstack(NULL, &ss) < 0) 265 return -1; 266 267 assert(!(ss.ss_flags & SS_ONSTACK)); 268 if (ss.ss_flags & SS_DISABLE) { 269 // Allocate an alternate signal stack. 270 ss.ss_size = 64*1024; 271 stk = malloc(ss.ss_size); 272 if (stk == NULL) 273 return -1; 274 ss.ss_flags = 0; 275 ss.ss_sp = stk; 276 if (sigaltstack(&ss, NULL) < 0) { 277 free(stk); 278 return -1; 279 } 280 } 281 282 // Register our signal handler. 283 memset(&sa, 0, sizeof sa); 284 sa.sa_handler = (void*)sighandler; 285 sa.sa_flags = SA_ONSTACK | SA_SIGINFO; 286 if (sigemptyset(&sa.sa_mask) < 0) 287 return -1; 288 if (sigaction(SIGSEGV, &sa, NULL) < 0) 289 return -1; 290 if (sigaction(SIGBUS, &sa, NULL) < 0) 291 return -1; 292 if (sigaction(SIGFPE, &sa, NULL) < 0) 293 return -1; 294 if (sigaction(SIGVTALRM, &sa, NULL) < 0) 295 return -1; 296 if (sigaction(SIGTRAP, &sa, NULL) < 0) 297 return -1; 298 return 0; 299 } 300