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) { | ... | ... |