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,18 +38,213 @@ | ||
38 | #define MAX_PACKET_LENGTH 4096 | 38 | #define MAX_PACKET_LENGTH 4096 |
39 | 39 | ||
40 | #include "qemu_socket.h" | 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 | #else | 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 | #endif | 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 | //#define DEBUG_GDB | 248 | //#define DEBUG_GDB |
54 | 249 | ||
55 | typedef struct GDBRegisterState { | 250 | typedef struct GDBRegisterState { |
@@ -1300,7 +1495,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | @@ -1300,7 +1495,7 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | ||
1300 | switch(ch) { | 1495 | switch(ch) { |
1301 | case '?': | 1496 | case '?': |
1302 | /* TODO: Make this return the correct value for user-mode. */ | 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 | s->c_cpu->cpu_index+1); | 1499 | s->c_cpu->cpu_index+1); |
1305 | put_packet(s, buf); | 1500 | put_packet(s, buf); |
1306 | /* Remove all the breakpoints when this query is issued, | 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,10 +1526,13 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf) | ||
1331 | s->c_cpu->pc = addr; | 1526 | s->c_cpu->pc = addr; |
1332 | #endif | 1527 | #endif |
1333 | } | 1528 | } |
1529 | + s->signal = 0; | ||
1334 | gdb_continue(s); | 1530 | gdb_continue(s); |
1335 | return RS_IDLE; | 1531 | return RS_IDLE; |
1336 | case 'C': | 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 | gdb_continue(s); | 1536 | gdb_continue(s); |
1339 | return RS_IDLE; | 1537 | return RS_IDLE; |
1340 | case 'k': | 1538 | case 'k': |
@@ -1692,16 +1890,16 @@ static void gdb_vm_stopped(void *opaque, int reason) | @@ -1692,16 +1890,16 @@ static void gdb_vm_stopped(void *opaque, int reason) | ||
1692 | } | 1890 | } |
1693 | snprintf(buf, sizeof(buf), | 1891 | snprintf(buf, sizeof(buf), |
1694 | "T%02xthread:%02x;%swatch:" TARGET_FMT_lx ";", | 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 | env->watchpoint_hit->vaddr); | 1894 | env->watchpoint_hit->vaddr); |
1697 | put_packet(s, buf); | 1895 | put_packet(s, buf); |
1698 | env->watchpoint_hit = NULL; | 1896 | env->watchpoint_hit = NULL; |
1699 | return; | 1897 | return; |
1700 | } | 1898 | } |
1701 | tb_flush(env); | 1899 | tb_flush(env); |
1702 | - ret = SIGTRAP; | 1900 | + ret = GDB_SIGNAL_TRAP; |
1703 | } else if (reason == EXCP_INTERRUPT) { | 1901 | } else if (reason == EXCP_INTERRUPT) { |
1704 | - ret = SIGINT; | 1902 | + ret = GDB_SIGNAL_INT; |
1705 | } else { | 1903 | } else { |
1706 | ret = 0; | 1904 | ret = 0; |
1707 | } | 1905 | } |
@@ -1853,6 +2051,19 @@ static void gdb_read_byte(GDBState *s, int ch) | @@ -1853,6 +2051,19 @@ static void gdb_read_byte(GDBState *s, int ch) | ||
1853 | 2051 | ||
1854 | #ifdef CONFIG_USER_ONLY | 2052 | #ifdef CONFIG_USER_ONLY |
1855 | int | 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 | gdb_handlesig (CPUState *env, int sig) | 2067 | gdb_handlesig (CPUState *env, int sig) |
1857 | { | 2068 | { |
1858 | GDBState *s; | 2069 | GDBState *s; |
@@ -1869,7 +2080,7 @@ gdb_handlesig (CPUState *env, int sig) | @@ -1869,7 +2080,7 @@ gdb_handlesig (CPUState *env, int sig) | ||
1869 | 2080 | ||
1870 | if (sig != 0) | 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 | put_packet(s, buf); | 2084 | put_packet(s, buf); |
1874 | } | 2085 | } |
1875 | /* put_packet() might have detected that the peer terminated the | 2086 | /* put_packet() might have detected that the peer terminated the |
@@ -1915,6 +2126,19 @@ void gdb_exit(CPUState *env, int code) | @@ -1915,6 +2126,19 @@ void gdb_exit(CPUState *env, int code) | ||
1915 | put_packet(s, buf); | 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 | static void gdb_accept(void) | 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,8 +10,10 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...); | ||
10 | int use_gdb_syscalls(void); | 10 | int use_gdb_syscalls(void); |
11 | void gdb_set_stop_cpu(CPUState *env); | 11 | void gdb_set_stop_cpu(CPUState *env); |
12 | #ifdef CONFIG_USER_ONLY | 12 | #ifdef CONFIG_USER_ONLY |
13 | +int gdb_queuesig (void); | ||
13 | int gdb_handlesig (CPUState *, int); | 14 | int gdb_handlesig (CPUState *, int); |
14 | void gdb_exit(CPUState *, int); | 15 | void gdb_exit(CPUState *, int); |
16 | +void gdb_signalled(CPUState *, int); | ||
15 | int gdbserver_start(int); | 17 | int gdbserver_start(int); |
16 | void gdbserver_fork(CPUState *); | 18 | void gdbserver_fork(CPUState *); |
17 | #else | 19 | #else |
linux-user/signal.c
@@ -264,6 +264,26 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) | @@ -264,6 +264,26 @@ void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo) | ||
264 | (void *)(long)tswapl(tinfo->_sifields._rt._sigval.sival_ptr); | 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 | void signal_init(void) | 287 | void signal_init(void) |
268 | { | 288 | { |
269 | struct sigaction act; | 289 | struct sigaction act; |
@@ -298,10 +318,12 @@ void signal_init(void) | @@ -298,10 +318,12 @@ void signal_init(void) | ||
298 | } | 318 | } |
299 | /* If there's already a handler installed then something has | 319 | /* If there's already a handler installed then something has |
300 | gone horribly wrong, so don't even try to handle that case. */ | 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 | sigaction(host_sig, &act, NULL); | 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,6 +354,7 @@ static void __attribute((noreturn)) force_sig(int sig) | ||
332 | fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", | 354 | fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", |
333 | sig, strsignal(host_sig)); | 355 | sig, strsignal(host_sig)); |
334 | #if 1 | 356 | #if 1 |
357 | + gdb_signalled(thread_env, sig); | ||
335 | _exit(-host_sig); | 358 | _exit(-host_sig); |
336 | #else | 359 | #else |
337 | { | 360 | { |
@@ -353,14 +376,16 @@ int queue_signal(CPUState *env, int sig, target_siginfo_t *info) | @@ -353,14 +376,16 @@ int queue_signal(CPUState *env, int sig, target_siginfo_t *info) | ||
353 | struct emulated_sigtable *k; | 376 | struct emulated_sigtable *k; |
354 | struct sigqueue *q, **pq; | 377 | struct sigqueue *q, **pq; |
355 | abi_ulong handler; | 378 | abi_ulong handler; |
379 | + int queue; | ||
356 | 380 | ||
357 | #if defined(DEBUG_SIGNAL) | 381 | #if defined(DEBUG_SIGNAL) |
358 | fprintf(stderr, "queue_signal: sig=%d\n", | 382 | fprintf(stderr, "queue_signal: sig=%d\n", |
359 | sig); | 383 | sig); |
360 | #endif | 384 | #endif |
361 | k = &ts->sigtab[sig - 1]; | 385 | k = &ts->sigtab[sig - 1]; |
386 | + queue = gdb_queuesig (); | ||
362 | handler = sigact_table[sig - 1]._sa_handler; | 387 | handler = sigact_table[sig - 1]._sa_handler; |
363 | - if (handler == TARGET_SIG_DFL) { | 388 | + if (!queue && handler == TARGET_SIG_DFL) { |
364 | if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) { | 389 | if (sig == TARGET_SIGTSTP || sig == TARGET_SIGTTIN || sig == TARGET_SIGTTOU) { |
365 | kill(getpid(),SIGSTOP); | 390 | kill(getpid(),SIGSTOP); |
366 | return 0; | 391 | return 0; |
@@ -374,10 +399,10 @@ int queue_signal(CPUState *env, int sig, target_siginfo_t *info) | @@ -374,10 +399,10 @@ int queue_signal(CPUState *env, int sig, target_siginfo_t *info) | ||
374 | } else { | 399 | } else { |
375 | return 0; /* indicate ignored */ | 400 | return 0; /* indicate ignored */ |
376 | } | 401 | } |
377 | - } else if (handler == TARGET_SIG_IGN) { | 402 | + } else if (!queue && handler == TARGET_SIG_IGN) { |
378 | /* ignore signal */ | 403 | /* ignore signal */ |
379 | return 0; | 404 | return 0; |
380 | - } else if (handler == TARGET_SIG_ERR) { | 405 | + } else if (!queue && handler == TARGET_SIG_ERR) { |
381 | force_sig(sig); | 406 | force_sig(sig); |
382 | } else { | 407 | } else { |
383 | pq = &k->first; | 408 | pq = &k->first; |
@@ -417,7 +442,8 @@ static void host_signal_handler(int host_signum, siginfo_t *info, | @@ -417,7 +442,8 @@ static void host_signal_handler(int host_signum, siginfo_t *info, | ||
417 | 442 | ||
418 | /* the CPU emulator uses some host signals to detect exceptions, | 443 | /* the CPU emulator uses some host signals to detect exceptions, |
419 | we we forward to it some signals */ | 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 | if (cpu_signal_handler(host_signum, info, puc)) | 447 | if (cpu_signal_handler(host_signum, info, puc)) |
422 | return; | 448 | return; |
423 | } | 449 | } |
@@ -544,7 +570,10 @@ int do_sigaction(int sig, const struct target_sigaction *act, | @@ -544,7 +570,10 @@ int do_sigaction(int sig, const struct target_sigaction *act, | ||
544 | if (k->_sa_handler == TARGET_SIG_IGN) { | 570 | if (k->_sa_handler == TARGET_SIG_IGN) { |
545 | act1.sa_sigaction = (void *)SIG_IGN; | 571 | act1.sa_sigaction = (void *)SIG_IGN; |
546 | } else if (k->_sa_handler == TARGET_SIG_DFL) { | 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 | } else { | 577 | } else { |
549 | act1.sa_sigaction = host_signal_handler; | 578 | act1.sa_sigaction = host_signal_handler; |
550 | } | 579 | } |
@@ -3107,17 +3136,21 @@ void process_pending_signals(CPUState *cpu_env) | @@ -3107,17 +3136,21 @@ void process_pending_signals(CPUState *cpu_env) | ||
3107 | 3136 | ||
3108 | sig = gdb_handlesig (cpu_env, sig); | 3137 | sig = gdb_handlesig (cpu_env, sig); |
3109 | if (!sig) { | 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 | if (handler == TARGET_SIG_DFL) { | 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 | force_sig(sig); | 3154 | force_sig(sig); |
3122 | } | 3155 | } |
3123 | } else if (handler == TARGET_SIG_IGN) { | 3156 | } else if (handler == TARGET_SIG_IGN) { |