Commit ca587a8ebdb4bfb30d3080ea5721882209911670

Authored by aurel32
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
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) {
... ...