Commit ca587a8ebdb4bfb30d3080ea5721882209911670
1 parent
2b1319c8
User-mode GDB stub improvements - handle signals
Handle signals in the user-mode GDB stub. Report them to GDB, and allow it to change or cancel them. Also correct the protocol numbering; it happens to match Linux numbering for SIGINT and SIGTRAP, but that's just good fortune. Signed-off-by: Daniel Jacobowitz <dan@codesourcery.com> Acked-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6096 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
290 additions
and
31 deletions
gdbstub.c
| ... | ... | @@ -38,18 +38,213 @@ |
| 38 | 38 | #define MAX_PACKET_LENGTH 4096 |
| 39 | 39 | |
| 40 | 40 | #include "qemu_socket.h" |
| 41 | -#ifdef _WIN32 | |
| 42 | -/* XXX: these constants may be independent of the host ones even for Unix */ | |
| 43 | -#ifndef SIGTRAP | |
| 44 | -#define SIGTRAP 5 | |
| 45 | -#endif | |
| 46 | -#ifndef SIGINT | |
| 47 | -#define SIGINT 2 | |
| 48 | -#endif | |
| 41 | + | |
| 42 | + | |
| 43 | +enum { | |
| 44 | + GDB_SIGNAL_0 = 0, | |
| 45 | + GDB_SIGNAL_INT = 2, | |
| 46 | + GDB_SIGNAL_TRAP = 5, | |
| 47 | + GDB_SIGNAL_UNKNOWN = 143 | |
| 48 | +}; | |
| 49 | + | |
| 50 | +#ifdef CONFIG_USER_ONLY | |
| 51 | + | |
| 52 | +/* Map target signal numbers to GDB protocol signal numbers and vice | |
| 53 | + * versa. For user emulation's currently supported systems, we can | |
| 54 | + * assume most signals are defined. | |
| 55 | + */ | |
| 56 | + | |
| 57 | +static int gdb_signal_table[] = { | |
| 58 | + 0, | |
| 59 | + TARGET_SIGHUP, | |
| 60 | + TARGET_SIGINT, | |
| 61 | + TARGET_SIGQUIT, | |
| 62 | + TARGET_SIGILL, | |
| 63 | + TARGET_SIGTRAP, | |
| 64 | + TARGET_SIGABRT, | |
| 65 | + -1, /* SIGEMT */ | |
| 66 | + TARGET_SIGFPE, | |
| 67 | + TARGET_SIGKILL, | |
| 68 | + TARGET_SIGBUS, | |
| 69 | + TARGET_SIGSEGV, | |
| 70 | + TARGET_SIGSYS, | |
| 71 | + TARGET_SIGPIPE, | |
| 72 | + TARGET_SIGALRM, | |
| 73 | + TARGET_SIGTERM, | |
| 74 | + TARGET_SIGURG, | |
| 75 | + TARGET_SIGSTOP, | |
| 76 | + TARGET_SIGTSTP, | |
| 77 | + TARGET_SIGCONT, | |
| 78 | + TARGET_SIGCHLD, | |
| 79 | + TARGET_SIGTTIN, | |
| 80 | + TARGET_SIGTTOU, | |
| 81 | + TARGET_SIGIO, | |
| 82 | + TARGET_SIGXCPU, | |
| 83 | + TARGET_SIGXFSZ, | |
| 84 | + TARGET_SIGVTALRM, | |
| 85 | + TARGET_SIGPROF, | |
| 86 | + TARGET_SIGWINCH, | |
| 87 | + -1, /* SIGLOST */ | |
| 88 | + TARGET_SIGUSR1, | |
| 89 | + TARGET_SIGUSR2, | |
| 90 | + TARGET_SIGPWR, | |
| 91 | + -1, /* SIGPOLL */ | |
| 92 | + -1, | |
| 93 | + -1, | |
| 94 | + -1, | |
| 95 | + -1, | |
| 96 | + -1, | |
| 97 | + -1, | |
| 98 | + -1, | |
| 99 | + -1, | |
| 100 | + -1, | |
| 101 | + -1, | |
| 102 | + -1, | |
| 103 | + __SIGRTMIN + 1, | |
| 104 | + __SIGRTMIN + 2, | |
| 105 | + __SIGRTMIN + 3, | |
| 106 | + __SIGRTMIN + 4, | |
| 107 | + __SIGRTMIN + 5, | |
| 108 | + __SIGRTMIN + 6, | |
| 109 | + __SIGRTMIN + 7, | |
| 110 | + __SIGRTMIN + 8, | |
| 111 | + __SIGRTMIN + 9, | |
| 112 | + __SIGRTMIN + 10, | |
| 113 | + __SIGRTMIN + 11, | |
| 114 | + __SIGRTMIN + 12, | |
| 115 | + __SIGRTMIN + 13, | |
| 116 | + __SIGRTMIN + 14, | |
| 117 | + __SIGRTMIN + 15, | |
| 118 | + __SIGRTMIN + 16, | |
| 119 | + __SIGRTMIN + 17, | |
| 120 | + __SIGRTMIN + 18, | |
| 121 | + __SIGRTMIN + 19, | |
| 122 | + __SIGRTMIN + 20, | |
| 123 | + __SIGRTMIN + 21, | |
| 124 | + __SIGRTMIN + 22, | |
| 125 | + __SIGRTMIN + 23, | |
| 126 | + __SIGRTMIN + 24, | |
| 127 | + __SIGRTMIN + 25, | |
| 128 | + __SIGRTMIN + 26, | |
| 129 | + __SIGRTMIN + 27, | |
| 130 | + __SIGRTMIN + 28, | |
| 131 | + __SIGRTMIN + 29, | |
| 132 | + __SIGRTMIN + 30, | |
| 133 | + __SIGRTMIN + 31, | |
| 134 | + -1, /* SIGCANCEL */ | |
| 135 | + __SIGRTMIN, | |
| 136 | + __SIGRTMIN + 32, | |
| 137 | + __SIGRTMIN + 33, | |
| 138 | + __SIGRTMIN + 34, | |
| 139 | + __SIGRTMIN + 35, | |
| 140 | + __SIGRTMIN + 36, | |
| 141 | + __SIGRTMIN + 37, | |
| 142 | + __SIGRTMIN + 38, | |
| 143 | + __SIGRTMIN + 39, | |
| 144 | + __SIGRTMIN + 40, | |
| 145 | + __SIGRTMIN + 41, | |
| 146 | + __SIGRTMIN + 42, | |
| 147 | + __SIGRTMIN + 43, | |
| 148 | + __SIGRTMIN + 44, | |
| 149 | + __SIGRTMIN + 45, | |
| 150 | + __SIGRTMIN + 46, | |
| 151 | + __SIGRTMIN + 47, | |
| 152 | + __SIGRTMIN + 48, | |
| 153 | + __SIGRTMIN + 49, | |
| 154 | + __SIGRTMIN + 50, | |
| 155 | + __SIGRTMIN + 51, | |
| 156 | + __SIGRTMIN + 52, | |
| 157 | + __SIGRTMIN + 53, | |
| 158 | + __SIGRTMIN + 54, | |
| 159 | + __SIGRTMIN + 55, | |
| 160 | + __SIGRTMIN + 56, | |
| 161 | + __SIGRTMIN + 57, | |
| 162 | + __SIGRTMIN + 58, | |
| 163 | + __SIGRTMIN + 59, | |
| 164 | + __SIGRTMIN + 60, | |
| 165 | + __SIGRTMIN + 61, | |
| 166 | + __SIGRTMIN + 62, | |
| 167 | + __SIGRTMIN + 63, | |
| 168 | + __SIGRTMIN + 64, | |
| 169 | + __SIGRTMIN + 65, | |
| 170 | + __SIGRTMIN + 66, | |
| 171 | + __SIGRTMIN + 67, | |
| 172 | + __SIGRTMIN + 68, | |
| 173 | + __SIGRTMIN + 69, | |
| 174 | + __SIGRTMIN + 70, | |
| 175 | + __SIGRTMIN + 71, | |
| 176 | + __SIGRTMIN + 72, | |
| 177 | + __SIGRTMIN + 73, | |
| 178 | + __SIGRTMIN + 74, | |
| 179 | + __SIGRTMIN + 75, | |
| 180 | + __SIGRTMIN + 76, | |
| 181 | + __SIGRTMIN + 77, | |
| 182 | + __SIGRTMIN + 78, | |
| 183 | + __SIGRTMIN + 79, | |
| 184 | + __SIGRTMIN + 80, | |
| 185 | + __SIGRTMIN + 81, | |
| 186 | + __SIGRTMIN + 82, | |
| 187 | + __SIGRTMIN + 83, | |
| 188 | + __SIGRTMIN + 84, | |
| 189 | + __SIGRTMIN + 85, | |
| 190 | + __SIGRTMIN + 86, | |
| 191 | + __SIGRTMIN + 87, | |
| 192 | + __SIGRTMIN + 88, | |
| 193 | + __SIGRTMIN + 89, | |
| 194 | + __SIGRTMIN + 90, | |
| 195 | + __SIGRTMIN + 91, | |
| 196 | + __SIGRTMIN + 92, | |
| 197 | + __SIGRTMIN + 93, | |
| 198 | + __SIGRTMIN + 94, | |
| 199 | + __SIGRTMIN + 95, | |
| 200 | + -1, /* SIGINFO */ | |
| 201 | + -1, /* UNKNOWN */ | |
| 202 | + -1, /* DEFAULT */ | |
| 203 | + -1, | |
| 204 | + -1, | |
| 205 | + -1, | |
| 206 | + -1, | |
| 207 | + -1, | |
| 208 | + -1 | |
| 209 | +}; | |
| 49 | 210 | #else |
| 50 | -#include <signal.h> | |
| 211 | +/* In system mode we only need SIGINT and SIGTRAP; other signals | |
| 212 | + are not yet supported. */ | |
| 213 | + | |
| 214 | +enum { | |
| 215 | + TARGET_SIGINT = 2, | |
| 216 | + TARGET_SIGTRAP = 5 | |
| 217 | +}; | |
| 218 | + | |
| 219 | +static int gdb_signal_table[] = { | |
| 220 | + -1, | |
| 221 | + -1, | |
| 222 | + TARGET_SIGINT, | |
| 223 | + -1, | |
| 224 | + -1, | |
| 225 | + TARGET_SIGTRAP | |
| 226 | +}; | |
| 227 | +#endif | |
| 228 | + | |
| 229 | +#ifdef CONFIG_USER_ONLY | |
| 230 | +static int target_signal_to_gdb (int sig) | |
| 231 | +{ | |
| 232 | + int i; | |
| 233 | + for (i = 0; i < ARRAY_SIZE (gdb_signal_table); i++) | |
| 234 | + if (gdb_signal_table[i] == sig) | |
| 235 | + return i; | |
| 236 | + return GDB_SIGNAL_UNKNOWN; | |
| 237 | +} | |
| 51 | 238 | #endif |
| 52 | 239 | |
| 240 | +static int gdb_signal_to_target (int sig) | |
| 241 | +{ | |
| 242 | + if (sig < ARRAY_SIZE (gdb_signal_table)) | |
| 243 | + return gdb_signal_table[sig]; | |
| 244 | + else | |
| 245 | + return -1; | |
| 246 | +} | |
| 247 | + | |
| 53 | 248 | //#define DEBUG_GDB |
| 54 | 249 | |
| 55 | 250 | typedef struct GDBRegisterState { |
| ... | ... | @@ -1300,7 +1495,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) |
| 1300 | 1495 | switch(ch) { |
| 1301 | 1496 | case '?': |
| 1302 | 1497 | /* TODO: Make this return the correct value for user-mode. */ |
| 1303 | - snprintf(buf, sizeof(buf), "T%02xthread:%02x;", SIGTRAP, | |
| 1498 | + snprintf(buf, sizeof(buf), "T%02xthread:%02x;", GDB_SIGNAL_TRAP, | |
| 1304 | 1499 | s->c_cpu->cpu_index+1); |
| 1305 | 1500 | put_packet(s, buf); |
| 1306 | 1501 | /* Remove all the breakpoints when this query is issued, |
| ... | ... | @@ -1331,10 +1526,13 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) |
| 1331 | 1526 | s->c_cpu->pc = addr; |
| 1332 | 1527 | #endif |
| 1333 | 1528 | } |
| 1529 | + s->signal = 0; | |
| 1334 | 1530 | gdb_continue(s); |
| 1335 | 1531 | return RS_IDLE; |
| 1336 | 1532 | case 'C': |
| 1337 | - s->signal = strtoul(p, (char **)&p, 16); | |
| 1533 | + s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16)); | |
| 1534 | + if (s->signal == -1) | |
| 1535 | + s->signal = 0; | |
| 1338 | 1536 | gdb_continue(s); |
| 1339 | 1537 | return RS_IDLE; |
| 1340 | 1538 | case 'k': |
| ... | ... | @@ -1692,16 +1890,16 @@ static void gdb_vm_stopped(void *opaque, int reason) |
| 1692 | 1890 | } |
| 1693 | 1891 | snprintf(buf, sizeof(buf), |
| 1694 | 1892 | "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";", |
| 1695 | - SIGTRAP, env->cpu_index+1, type, | |
| 1893 | + GDB_SIGNAL_TRAP, env->cpu_index+1, type, | |
| 1696 | 1894 | env->watchpoint_hit->vaddr); |
| 1697 | 1895 | put_packet(s, buf); |
| 1698 | 1896 | env->watchpoint_hit = NULL; |
| 1699 | 1897 | return; |
| 1700 | 1898 | } |
| 1701 | 1899 | tb_flush(env); |
| 1702 | - ret = SIGTRAP; | |
| 1900 | + ret = GDB_SIGNAL_TRAP; | |
| 1703 | 1901 | } else if (reason == EXCP_INTERRUPT) { |
| 1704 | - ret = SIGINT; | |
| 1902 | + ret = GDB_SIGNAL_INT; | |
| 1705 | 1903 | } else { |
| 1706 | 1904 | ret = 0; |
| 1707 | 1905 | } |
| ... | ... | @@ -1853,6 +2051,19 @@ static void gdb_read_byte(GDBState *s, int ch) |
| 1853 | 2051 | |
| 1854 | 2052 | #ifdef CONFIG_USER_ONLY |
| 1855 | 2053 | int |
| 2054 | +gdb_queuesig (void) | |
| 2055 | +{ | |
| 2056 | + GDBState *s; | |
| 2057 | + | |
| 2058 | + s = gdbserver_state; | |
| 2059 | + | |
| 2060 | + if (gdbserver_fd < 0 || s->fd < 0) | |
| 2061 | + return 0; | |
| 2062 | + else | |
| 2063 | + return 1; | |
| 2064 | +} | |
| 2065 | + | |
| 2066 | +int | |
| 1856 | 2067 | gdb_handlesig (CPUState *env, int sig) |
| 1857 | 2068 | { |
| 1858 | 2069 | GDBState *s; |
| ... | ... | @@ -1869,7 +2080,7 @@ gdb_handlesig (CPUState *env, int sig) |
| 1869 | 2080 | |
| 1870 | 2081 | if (sig != 0) |
| 1871 | 2082 | { |
| 1872 | - snprintf(buf, sizeof(buf), "S%02x", sig); | |
| 2083 | + snprintf(buf, sizeof(buf), "S%02x", target_signal_to_gdb (sig)); | |
| 1873 | 2084 | put_packet(s, buf); |
| 1874 | 2085 | } |
| 1875 | 2086 | /* put_packet() might have detected that the peer terminated the |
| ... | ... | @@ -1915,6 +2126,19 @@ void gdb_exit(CPUState *env, int code) |
| 1915 | 2126 | put_packet(s, buf); |
| 1916 | 2127 | } |
| 1917 | 2128 | |
| 2129 | +/* Tell the remote gdb that the process has exited due to SIG. */ | |
| 2130 | +void gdb_signalled(CPUState *env, int sig) | |
| 2131 | +{ | |
| 2132 | + GDBState *s; | |
| 2133 | + char buf[4]; | |
| 2134 | + | |
| 2135 | + s = gdbserver_state; | |
| 2136 | + if (gdbserver_fd < 0 || s->fd < 0) | |
| 2137 | + return; | |
| 2138 | + | |
| 2139 | + snprintf(buf, sizeof(buf), "X%02x", target_signal_to_gdb (sig)); | |
| 2140 | + put_packet(s, buf); | |
| 2141 | +} | |
| 1918 | 2142 | |
| 1919 | 2143 | static void gdb_accept(void) |
| 1920 | 2144 | { | ... | ... |
gdbstub.h
| ... | ... | @@ -10,8 +10,10 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...); |
| 10 | 10 | int use_gdb_syscalls(void); |
| 11 | 11 | void gdb_set_stop_cpu(CPUState *env); |
| 12 | 12 | #ifdef CONFIG_USER_ONLY |
| 13 | +int gdb_queuesig (void); | |
| 13 | 14 | int gdb_handlesig (CPUState *, int); |
| 14 | 15 | void gdb_exit(CPUState *, int); |
| 16 | +void gdb_signalled(CPUState *, int); | |
| 15 | 17 | int gdbserver_start(int); |
| 16 | 18 | void gdbserver_fork(CPUState *); |
| 17 | 19 | #else | ... | ... |
linux-user/signal.c
| ... | ... | @@ -264,6 +264,26 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) |
| 264 | 264 | (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr); |
| 265 | 265 | } |
| 266 | 266 | |
| 267 | +static int fatal_signal (int sig) | |
| 268 | +{ | |
| 269 | + switch (sig) { | |
| 270 | + case TARGET_SIGCHLD: | |
| 271 | + case TARGET_SIGURG: | |
| 272 | + case TARGET_SIGWINCH: | |
| 273 | + /* Ignored by default. */ | |
| 274 | + return 0; | |
| 275 | + case TARGET_SIGCONT: | |
| 276 | + case TARGET_SIGSTOP: | |
| 277 | + case TARGET_SIGTSTP: | |
| 278 | + case TARGET_SIGTTIN: | |
| 279 | + case TARGET_SIGTTOU: | |
| 280 | + /* Job control signals. */ | |
| 281 | + return 0; | |
| 282 | + default: | |
| 283 | + return 1; | |
| 284 | + } | |
| 285 | +} | |
| 286 | + | |
| 267 | 287 | void signal_init(void) |
| 268 | 288 | { |
| 269 | 289 | struct sigaction act; |
| ... | ... | @@ -298,10 +318,12 @@ void signal_init(void) |
| 298 | 318 | } |
| 299 | 319 | /* If there's already a handler installed then something has |
| 300 | 320 | gone horribly wrong, so don't even try to handle that case. */ |
| 301 | - /* Install some handlers for our own use. */ | |
| 302 | - if (host_sig == SIGSEGV || host_sig == SIGBUS) { | |
| 321 | + /* Install some handlers for our own use. We need at least | |
| 322 | + SIGSEGV and SIGBUS, to detect exceptions. We can not just | |
| 323 | + trap all signals because it affects syscall interrupt | |
| 324 | + behavior. But do trap all default-fatal signals. */ | |
| 325 | + if (fatal_signal (i)) | |
| 303 | 326 | sigaction(host_sig, &act, NULL); |
| 304 | - } | |
| 305 | 327 | } |
| 306 | 328 | } |
| 307 | 329 | |
| ... | ... | @@ -332,6 +354,7 @@ static void __attribute((noreturn)) force_sig(int sig) |
| 332 | 354 | fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", |
| 333 | 355 | sig, strsignal(host_sig)); |
| 334 | 356 | #if 1 |
| 357 | + gdb_signalled(thread_env, sig); | |
| 335 | 358 | _exit(-host_sig); |
| 336 | 359 | #else |
| 337 | 360 | { |
| ... | ... | @@ -353,14 +376,16 @@ int queue_signal(CPUState *env, int sig, target_siginfo_t *info) |
| 353 | 376 | struct emulated_sigtable *k; |
| 354 | 377 | struct sigqueue *q, **pq; |
| 355 | 378 | abi_ulong handler; |
| 379 | + int queue; | |
| 356 | 380 | |
| 357 | 381 | #if defined(DEBUG_SIGNAL) |
| 358 | 382 | fprintf(stderr, "queue_signal: sig=%d\n", |
| 359 | 383 | sig); |
| 360 | 384 | #endif |
| 361 | 385 | k = &ts->sigtab[sig - 1]; |
| 386 | + queue = gdb_queuesig (); | |
| 362 | 387 | handler = sigact_table[sig - 1]._sa_handler; |
| 363 | - if (handler == TARGET_SIG_DFL) { | |
| 388 | + if (!queue && handler == TARGET_SIG_DFL) { | |
| 364 | 389 | if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) { |
| 365 | 390 | kill(getpid(),SIGSTOP); |
| 366 | 391 | return 0; |
| ... | ... | @@ -374,10 +399,10 @@ int queue_signal(CPUState *env, int sig, target_siginfo_t *info) |
| 374 | 399 | } else { |
| 375 | 400 | return 0; /* indicate ignored */ |
| 376 | 401 | } |
| 377 | - } else if (handler == TARGET_SIG_IGN) { | |
| 402 | + } else if (!queue && handler == TARGET_SIG_IGN) { | |
| 378 | 403 | /* ignore signal */ |
| 379 | 404 | return 0; |
| 380 | - } else if (handler == TARGET_SIG_ERR) { | |
| 405 | + } else if (!queue && handler == TARGET_SIG_ERR) { | |
| 381 | 406 | force_sig(sig); |
| 382 | 407 | } else { |
| 383 | 408 | pq = &k->first; |
| ... | ... | @@ -417,7 +442,8 @@ static void host_signal_handler(int host_signum, siginfo_t *info, |
| 417 | 442 | |
| 418 | 443 | /* the CPU emulator uses some host signals to detect exceptions, |
| 419 | 444 | we we forward to it some signals */ |
| 420 | - if (host_signum == SIGSEGV || host_signum == SIGBUS) { | |
| 445 | + if ((host_signum == SIGSEGV || host_signum == SIGBUS) | |
| 446 | + && info->si_code == SI_KERNEL) { | |
| 421 | 447 | if (cpu_signal_handler(host_signum, info, puc)) |
| 422 | 448 | return; |
| 423 | 449 | } |
| ... | ... | @@ -544,7 +570,10 @@ int do_sigaction(int sig, const struct target_sigaction *act, |
| 544 | 570 | if (k->_sa_handler == TARGET_SIG_IGN) { |
| 545 | 571 | act1.sa_sigaction = (void *)SIG_IGN; |
| 546 | 572 | } else if (k->_sa_handler == TARGET_SIG_DFL) { |
| 547 | - act1.sa_sigaction = (void *)SIG_DFL; | |
| 573 | + if (fatal_signal (sig)) | |
| 574 | + act1.sa_sigaction = host_signal_handler; | |
| 575 | + else | |
| 576 | + act1.sa_sigaction = (void *)SIG_DFL; | |
| 548 | 577 | } else { |
| 549 | 578 | act1.sa_sigaction = host_signal_handler; |
| 550 | 579 | } |
| ... | ... | @@ -3107,17 +3136,21 @@ void process_pending_signals(CPUState *cpu_env) |
| 3107 | 3136 | |
| 3108 | 3137 | sig = gdb_handlesig (cpu_env, sig); |
| 3109 | 3138 | if (!sig) { |
| 3110 | - fprintf (stderr, "Lost signal\n"); | |
| 3111 | - abort(); | |
| 3139 | + sa = NULL; | |
| 3140 | + handler = TARGET_SIG_IGN; | |
| 3141 | + } else { | |
| 3142 | + sa = &sigact_table[sig - 1]; | |
| 3143 | + handler = sa->_sa_handler; | |
| 3112 | 3144 | } |
| 3113 | 3145 | |
| 3114 | - sa = &sigact_table[sig - 1]; | |
| 3115 | - handler = sa->_sa_handler; | |
| 3116 | 3146 | if (handler == TARGET_SIG_DFL) { |
| 3117 | - /* default handler : ignore some signal. The other are fatal */ | |
| 3118 | - if (sig != TARGET_SIGCHLD && | |
| 3119 | - sig != TARGET_SIGURG && | |
| 3120 | - sig != TARGET_SIGWINCH) { | |
| 3147 | + /* default handler : ignore some signal. The other are job control or fatal */ | |
| 3148 | + if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) { | |
| 3149 | + kill(getpid(),SIGSTOP); | |
| 3150 | + } else if (sig != TARGET_SIGCHLD && | |
| 3151 | + sig != TARGET_SIGURG && | |
| 3152 | + sig != TARGET_SIGWINCH && | |
| 3153 | + sig != TARGET_SIGCONT) { | |
| 3121 | 3154 | force_sig(sig); |
| 3122 | 3155 | } |
| 3123 | 3156 | } else if (handler == TARGET_SIG_IGN) { | ... | ... |