Revision 5fafdf24 linux-user/signal.c
b/linux-user/signal.c | ||
---|---|---|
1 | 1 |
/* |
2 | 2 |
* Emulation of Linux signals |
3 |
*
|
|
3 |
* |
|
4 | 4 |
* Copyright (c) 2003 Fabrice Bellard |
5 | 5 |
* |
6 | 6 |
* This program is free software; you can redistribute it and/or modify |
... | ... | |
50 | 50 |
static struct sigqueue *first_free; /* first free siginfo queue entry */ |
51 | 51 |
static int signal_pending; /* non zero if a signal may be pending */ |
52 | 52 |
|
53 |
static void host_signal_handler(int host_signum, siginfo_t *info,
|
|
53 |
static void host_signal_handler(int host_signum, siginfo_t *info, |
|
54 | 54 |
void *puc); |
55 | 55 |
|
56 | 56 |
static uint8_t host_to_target_signal_table[65] = { |
... | ... | |
102 | 102 |
return target_to_host_signal_table[sig]; |
103 | 103 |
} |
104 | 104 |
|
105 |
static void host_to_target_sigset_internal(target_sigset_t *d,
|
|
105 |
static void host_to_target_sigset_internal(target_sigset_t *d, |
|
106 | 106 |
const sigset_t *s) |
107 | 107 |
{ |
108 | 108 |
int i; |
109 | 109 |
unsigned long sigmask; |
110 | 110 |
uint32_t target_sigmask; |
111 |
|
|
111 |
|
|
112 | 112 |
sigmask = ((unsigned long *)s)[0]; |
113 | 113 |
target_sigmask = 0; |
114 | 114 |
for(i = 0; i < 32; i++) { |
115 |
if (sigmask & (1 << i))
|
|
115 |
if (sigmask & (1 << i)) |
|
116 | 116 |
target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1); |
117 | 117 |
} |
118 | 118 |
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 |
... | ... | |
147 | 147 |
target_sigmask = s->sig[0]; |
148 | 148 |
sigmask = 0; |
149 | 149 |
for(i = 0; i < 32; i++) { |
150 |
if (target_sigmask & (1 << i))
|
|
150 |
if (target_sigmask & (1 << i)) |
|
151 | 151 |
sigmask |= 1 << (target_to_host_signal(i + 1) - 1); |
152 | 152 |
} |
153 | 153 |
#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32 |
... | ... | |
171 | 171 |
s1.sig[i] = tswapl(s->sig[i]); |
172 | 172 |
target_to_host_sigset_internal(d, &s1); |
173 | 173 |
} |
174 |
|
|
175 |
void host_to_target_old_sigset(target_ulong *old_sigset,
|
|
174 |
|
|
175 |
void host_to_target_old_sigset(target_ulong *old_sigset, |
|
176 | 176 |
const sigset_t *sigset) |
177 | 177 |
{ |
178 | 178 |
target_sigset_t d; |
... | ... | |
180 | 180 |
*old_sigset = d.sig[0]; |
181 | 181 |
} |
182 | 182 |
|
183 |
void target_to_host_old_sigset(sigset_t *sigset,
|
|
183 |
void target_to_host_old_sigset(sigset_t *sigset, |
|
184 | 184 |
const target_ulong *old_sigset) |
185 | 185 |
{ |
186 | 186 |
target_sigset_t d; |
... | ... | |
194 | 194 |
|
195 | 195 |
/* siginfo conversion */ |
196 | 196 |
|
197 |
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
|
|
197 |
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, |
|
198 | 198 |
const siginfo_t *info) |
199 | 199 |
{ |
200 | 200 |
int sig; |
... | ... | |
202 | 202 |
tinfo->si_signo = sig; |
203 | 203 |
tinfo->si_errno = 0; |
204 | 204 |
tinfo->si_code = 0; |
205 |
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
|
|
205 |
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || |
|
206 | 206 |
sig == SIGBUS || sig == SIGTRAP) { |
207 | 207 |
/* should never come here, but who knows. The information for |
208 | 208 |
the target is irrelevant */ |
... | ... | |
213 | 213 |
tinfo->_sifields._rt._pid = info->si_pid; |
214 | 214 |
tinfo->_sifields._rt._uid = info->si_uid; |
215 | 215 |
/* XXX: potential problem if 64 bit */ |
216 |
tinfo->_sifields._rt._sigval.sival_ptr =
|
|
216 |
tinfo->_sifields._rt._sigval.sival_ptr = |
|
217 | 217 |
(target_ulong)info->si_value.sival_ptr; |
218 | 218 |
} |
219 | 219 |
} |
220 | 220 |
|
221 |
static void tswap_siginfo(target_siginfo_t *tinfo,
|
|
221 |
static void tswap_siginfo(target_siginfo_t *tinfo, |
|
222 | 222 |
const target_siginfo_t *info) |
223 | 223 |
{ |
224 | 224 |
int sig; |
... | ... | |
226 | 226 |
tinfo->si_signo = tswap32(sig); |
227 | 227 |
tinfo->si_errno = tswap32(info->si_errno); |
228 | 228 |
tinfo->si_code = tswap32(info->si_code); |
229 |
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
|
|
229 |
if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || |
|
230 | 230 |
sig == SIGBUS || sig == SIGTRAP) { |
231 |
tinfo->_sifields._sigfault._addr =
|
|
231 |
tinfo->_sifields._sigfault._addr = |
|
232 | 232 |
tswapl(info->_sifields._sigfault._addr); |
233 | 233 |
} else if (sig == SIGIO) { |
234 | 234 |
tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd); |
235 | 235 |
} else if (sig >= TARGET_SIGRTMIN) { |
236 | 236 |
tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid); |
237 | 237 |
tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid); |
238 |
tinfo->_sifields._rt._sigval.sival_ptr =
|
|
238 |
tinfo->_sifields._rt._sigval.sival_ptr = |
|
239 | 239 |
tswapl(info->_sifields._rt._sigval.sival_ptr); |
240 | 240 |
} |
241 | 241 |
} |
... | ... | |
256 | 256 |
info->si_code = tswap32(tinfo->si_code); |
257 | 257 |
info->si_pid = tswap32(tinfo->_sifields._rt._pid); |
258 | 258 |
info->si_uid = tswap32(tinfo->_sifields._rt._uid); |
259 |
info->si_value.sival_ptr =
|
|
259 |
info->si_value.sival_ptr = |
|
260 | 260 |
(void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr); |
261 | 261 |
} |
262 | 262 |
|
... | ... | |
274 | 274 |
j = host_to_target_signal_table[i]; |
275 | 275 |
target_to_host_signal_table[j] = i; |
276 | 276 |
} |
277 |
|
|
277 |
|
|
278 | 278 |
/* set all host signal handlers. ALL signals are blocked during |
279 | 279 |
the handlers to serialize them. */ |
280 | 280 |
sigfillset(&act.sa_mask); |
... | ... | |
283 | 283 |
for(i = 1; i < NSIG; i++) { |
284 | 284 |
sigaction(i, &act, NULL); |
285 | 285 |
} |
286 |
|
|
286 |
|
|
287 | 287 |
memset(sigact_table, 0, sizeof(sigact_table)); |
288 | 288 |
|
289 | 289 |
first_free = &sigqueue_table[0]; |
290 |
for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
|
|
290 |
for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) |
|
291 | 291 |
sigqueue_table[i].next = &sigqueue_table[i + 1]; |
292 | 292 |
sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL; |
293 | 293 |
} |
... | ... | |
314 | 314 |
{ |
315 | 315 |
int host_sig; |
316 | 316 |
host_sig = target_to_host_signal(sig); |
317 |
fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
|
|
317 |
fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", |
|
318 | 318 |
sig, strsignal(host_sig)); |
319 | 319 |
#if 1 |
320 | 320 |
_exit(-host_sig); |
... | ... | |
339 | 339 |
target_ulong handler; |
340 | 340 |
|
341 | 341 |
#if defined(DEBUG_SIGNAL) |
342 |
fprintf(stderr, "queue_signal: sig=%d\n",
|
|
342 |
fprintf(stderr, "queue_signal: sig=%d\n", |
|
343 | 343 |
sig); |
344 | 344 |
#endif |
345 | 345 |
k = &sigact_table[sig - 1]; |
346 | 346 |
handler = k->sa._sa_handler; |
347 | 347 |
if (handler == TARGET_SIG_DFL) { |
348 | 348 |
/* default handler : ignore some signal. The other are fatal */ |
349 |
if (sig != TARGET_SIGCHLD &&
|
|
350 |
sig != TARGET_SIGURG &&
|
|
349 |
if (sig != TARGET_SIGCHLD && |
|
350 |
sig != TARGET_SIGURG && |
|
351 | 351 |
sig != TARGET_SIGWINCH) { |
352 | 352 |
force_sig(sig); |
353 | 353 |
} else { |
... | ... | |
388 | 388 |
} |
389 | 389 |
} |
390 | 390 |
|
391 |
static void host_signal_handler(int host_signum, siginfo_t *info,
|
|
391 |
static void host_signal_handler(int host_signum, siginfo_t *info, |
|
392 | 392 |
void *puc) |
393 | 393 |
{ |
394 | 394 |
int sig; |
... | ... | |
396 | 396 |
|
397 | 397 |
/* the CPU emulator uses some host signals to detect exceptions, |
398 | 398 |
we we forward to it some signals */ |
399 |
if (host_signum == SIGSEGV || host_signum == SIGBUS
|
|
399 |
if (host_signum == SIGSEGV || host_signum == SIGBUS |
|
400 | 400 |
#if defined(TARGET_I386) && defined(USE_CODE_COPY) |
401 | 401 |
|| host_signum == SIGFPE |
402 | 402 |
#endif |
... | ... | |
430 | 430 |
return -EINVAL; |
431 | 431 |
k = &sigact_table[sig - 1]; |
432 | 432 |
#if defined(DEBUG_SIGNAL) |
433 |
fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
|
|
433 |
fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n", |
|
434 | 434 |
sig, (int)act, (int)oact); |
435 | 435 |
#endif |
436 | 436 |
if (oact) { |
... | ... | |
476 | 476 |
#define offsetof(type, field) ((size_t) &((type *)0)->field) |
477 | 477 |
#endif |
478 | 478 |
|
479 |
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
|
|
479 |
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, |
|
480 | 480 |
const target_siginfo_t *info) |
481 | 481 |
{ |
482 | 482 |
tswap_siginfo(tinfo, info); |
... | ... | |
648 | 648 |
} |
649 | 649 |
|
650 | 650 |
/* This is the legacy signal stack switching. */ |
651 |
else
|
|
651 |
else |
|
652 | 652 |
#endif |
653 | 653 |
if ((env->segs[R_SS].selector & 0xffff) != __USER_DS && |
654 | 654 |
!(ka->sa.sa_flags & TARGET_SA_RESTORER) && |
... | ... | |
723 | 723 |
force_sig(TARGET_SIGSEGV /* , current */); |
724 | 724 |
} |
725 | 725 |
|
726 |
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
|
726 |
static void setup_rt_frame(int sig, struct emulated_sigaction *ka, |
|
727 | 727 |
target_siginfo_t *info, |
728 | 728 |
target_sigset_t *set, CPUX86State *env) |
729 | 729 |
{ |
... | ... | |
817 | 817 |
|
818 | 818 |
cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3); |
819 | 819 |
cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3); |
820 |
|
|
820 |
|
|
821 | 821 |
{ |
822 | 822 |
unsigned int tmpflags; |
823 | 823 |
tmpflags = ldl(&sc->eflags); |
... | ... | |
865 | 865 |
|
866 | 866 |
target_to_host_sigset_internal(&set, &target_set); |
867 | 867 |
sigprocmask(SIG_SETMASK, &set, NULL); |
868 |
|
|
868 |
|
|
869 | 869 |
/* restore registers */ |
870 | 870 |
if (restore_sigcontext(env, &frame->sc, &eax)) |
871 | 871 |
goto badframe; |
... | ... | |
889 | 889 |
#endif |
890 | 890 |
target_to_host_sigset(&set, &frame->uc.tuc_sigmask); |
891 | 891 |
sigprocmask(SIG_SETMASK, &set, NULL); |
892 |
|
|
892 |
|
|
893 | 893 |
if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax)) |
894 | 894 |
goto badframe; |
895 | 895 |
|
... | ... | |
1127 | 1127 |
// return err; |
1128 | 1128 |
} |
1129 | 1129 |
|
1130 |
static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
|
|
1130 |
static void setup_rt_frame(int usig, struct emulated_sigaction *ka, |
|
1131 | 1131 |
target_siginfo_t *info, |
1132 | 1132 |
target_sigset_t *set, CPUState *env) |
1133 | 1133 |
{ |
... | ... | |
1547 | 1547 |
} |
1548 | 1548 |
|
1549 | 1549 |
|
1550 |
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
|
1550 |
static void setup_rt_frame(int sig, struct emulated_sigaction *ka, |
|
1551 | 1551 |
target_siginfo_t *info, |
1552 | 1552 |
target_sigset_t *set, CPUState *env) |
1553 | 1553 |
{ |
... | ... | |
1851 | 1851 |
return g2h((sp - frame_size) & ~7); |
1852 | 1852 |
} |
1853 | 1853 |
|
1854 |
static void setup_frame(int sig, struct emulated_sigaction * ka,
|
|
1854 |
static void setup_frame(int sig, struct emulated_sigaction * ka, |
|
1855 | 1855 |
target_sigset_t *set, CPUState *regs) |
1856 | 1856 |
{ |
1857 | 1857 |
struct sigframe *frame; |
... | ... | |
1894 | 1894 |
|
1895 | 1895 |
give_sigsegv: |
1896 | 1896 |
force_sig(TARGET_SIGSEGV/*, current*/); |
1897 |
return;
|
|
1897 |
return; |
|
1898 | 1898 |
} |
1899 | 1899 |
|
1900 | 1900 |
long do_sigreturn(CPUState *regs) |
... | ... | |
1933 | 1933 |
:"r" (®s)); |
1934 | 1934 |
/* Unreached */ |
1935 | 1935 |
#endif |
1936 |
|
|
1936 |
|
|
1937 | 1937 |
regs->PC[regs->current_tc] = regs->CP0_EPC; |
1938 | 1938 |
/* I am not sure this is right, but it seems to work |
1939 | 1939 |
* maybe a problem with nested signals ? */ |
... | ... | |
1945 | 1945 |
return 0; |
1946 | 1946 |
} |
1947 | 1947 |
|
1948 |
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
|
1948 |
static void setup_rt_frame(int sig, struct emulated_sigaction *ka, |
|
1949 | 1949 |
target_siginfo_t *info, |
1950 | 1950 |
target_sigset_t *set, CPUState *env) |
1951 | 1951 |
{ |
... | ... | |
1966 | 1966 |
fprintf(stderr, "setup_frame: not implemented\n"); |
1967 | 1967 |
} |
1968 | 1968 |
|
1969 |
static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
|
|
1969 |
static void setup_rt_frame(int sig, struct emulated_sigaction *ka, |
|
1970 | 1970 |
target_siginfo_t *info, |
1971 | 1971 |
target_sigset_t *set, CPUState *env) |
1972 | 1972 |
{ |
... | ... | |
1995 | 1995 |
target_sigset_t target_old_set; |
1996 | 1996 |
struct emulated_sigaction *k; |
1997 | 1997 |
struct sigqueue *q; |
1998 |
|
|
1998 |
|
|
1999 | 1999 |
if (!signal_pending) |
2000 | 2000 |
return; |
2001 | 2001 |
|
... | ... | |
2018 | 2018 |
k->first = q->next; |
2019 | 2019 |
if (!k->first) |
2020 | 2020 |
k->pending = 0; |
2021 |
|
|
2021 |
|
|
2022 | 2022 |
sig = gdb_handlesig (cpu_env, sig); |
2023 | 2023 |
if (!sig) { |
2024 | 2024 |
fprintf (stderr, "Lost signal\n"); |
... | ... | |
2028 | 2028 |
handler = k->sa._sa_handler; |
2029 | 2029 |
if (handler == TARGET_SIG_DFL) { |
2030 | 2030 |
/* default handler : ignore some signal. The other are fatal */ |
2031 |
if (sig != TARGET_SIGCHLD &&
|
|
2032 |
sig != TARGET_SIGURG &&
|
|
2031 |
if (sig != TARGET_SIGCHLD && |
|
2032 |
sig != TARGET_SIGURG && |
|
2033 | 2033 |
sig != TARGET_SIGWINCH) { |
2034 | 2034 |
force_sig(sig); |
2035 | 2035 |
} |
... | ... | |
2044 | 2044 |
blocked during the handler */ |
2045 | 2045 |
if (!(k->sa.sa_flags & TARGET_SA_NODEFER)) |
2046 | 2046 |
sigaddset(&set, target_to_host_signal(sig)); |
2047 |
|
|
2047 |
|
|
2048 | 2048 |
/* block signals in the handler using Linux */ |
2049 | 2049 |
sigprocmask(SIG_BLOCK, &set, &old_set); |
2050 | 2050 |
/* save the previous blocked signal state to restore it at the |
Also available in: Unified diff