Revision 9de5e440 linux-user/signal.c

b/linux-user/signal.c
27 27

  
28 28
#include "gemu.h"
29 29

  
30
#include "syscall_defs.h"
31

  
32
#ifdef TARGET_I386
33
#include "cpu-i386.h"
34
#include "syscall-i386.h"
35
#endif
36

  
37 30
/* signal handling inspired from em86. */
38 31

  
39 32
//#define DEBUG_SIGNAL
......
42 35

  
43 36
struct sigqueue {
44 37
    struct sigqueue *next;
45
    siginfo_t info;
38
    target_siginfo_t info;
46 39
};
47 40

  
48 41
struct emulated_sigaction {
......
101 94
    *(unsigned long *)sigset = tswapl(*old_sigset);
102 95
}
103 96

  
104
/* XXX: finish it */
105
void host_to_target_siginfo(target_siginfo_t *tinfo, siginfo_t *info)
97
/* siginfo conversion */
98

  
99
static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, 
100
                                                 const siginfo_t *info)
106 101
{
107
    tinfo->si_signo = tswap32(info->si_signo);
102
    int sig;
103
    sig = host_to_target_signal(info->si_signo);
104
    tinfo->si_signo = sig;
105
    tinfo->si_errno = 0;
106
    tinfo->si_code = 0;
107
    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
108
        /* should never come here, but who knows. The information for
109
           the target is irrelevant */
110
        tinfo->_sifields._sigfault._addr = 0;
111
    } else if (sig >= TARGET_SIGRTMIN) {
112
        tinfo->_sifields._rt._pid = info->si_pid;
113
        tinfo->_sifields._rt._uid = info->si_uid;
114
        /* XXX: potential problem if 64 bit */
115
        tinfo->_sifields._rt._sigval.sival_ptr = 
116
            (target_ulong)info->si_value.sival_ptr;
117
    }
118
}
119

  
120
static void tswap_siginfo(target_siginfo_t *tinfo, 
121
                          const target_siginfo_t *info)
122
{
123
    int sig;
124
    sig = info->si_signo;
125
    tinfo->si_signo = tswap32(sig);
108 126
    tinfo->si_errno = tswap32(info->si_errno);
109 127
    tinfo->si_code = tswap32(info->si_code);
128
    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || sig == SIGBUS) {
129
        tinfo->_sifields._sigfault._addr = 
130
            tswapl(info->_sifields._sigfault._addr);
131
    } else if (sig >= TARGET_SIGRTMIN) {
132
        tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
133
        tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
134
        tinfo->_sifields._rt._sigval.sival_ptr = 
135
            tswapl(info->_sifields._rt._sigval.sival_ptr);
136
    }
137
}
138

  
139

  
140
void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
141
{
142
    host_to_target_siginfo_noswap(tinfo, info);
143
    tswap_siginfo(tinfo, tinfo);
110 144
}
111 145

  
112
/* XXX: finish it */
113
void target_to_host_siginfo(siginfo_t *info, target_siginfo_t *tinfo)
146
/* XXX: we support only POSIX RT signals are used. */
147
/* XXX: find a solution for 64 bit (additionnal malloced data is needed) */
148
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
114 149
{
115 150
    info->si_signo = tswap32(tinfo->si_signo);
116 151
    info->si_errno = tswap32(tinfo->si_errno);
117 152
    info->si_code = tswap32(tinfo->si_code);
153
    info->si_pid = tswap32(tinfo->_sifields._rt._pid);
154
    info->si_uid = tswap32(tinfo->_sifields._rt._uid);
155
    info->si_value.sival_ptr = 
156
        (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
118 157
}
119 158

  
120 159
void signal_init(void)
......
122 161
    struct sigaction act;
123 162
    int i;
124 163

  
125
    /* set all host signal handlers */
126
    sigemptyset(&act.sa_mask);
164
    /* set all host signal handlers. ALL signals are blocked during
165
       the handlers to serialize them. */
166
    sigfillset(&act.sa_mask);
127 167
    act.sa_flags = SA_SIGINFO;
128 168
    act.sa_sigaction = host_signal_handler;
129 169
    for(i = 1; i < NSIG; i++) {
......
155 195
    first_free = q;
156 196
}
157 197

  
158
static int queue_signal(struct emulated_sigaction *k, int sig, siginfo_t *info)
159
{
160
    struct sigqueue *q, **pq;
161

  
162
    pq = &k->first;
163
    if (!k->pending || sig < TARGET_SIGRTMIN) {
164
        /* first signal or non real time signal */
165
        q = &k->info;
166
    } else {
167
        q = alloc_sigqueue();
168
        if (!q)
169
            return -EAGAIN;
170
        while (*pq != NULL)
171
            pq = &(*pq)->next;
172
    }
173
    *pq = q;
174
    q->info = *info;
175
    q->next = NULL;
176
    k->pending = 1;
177
    /* signal that a new signal is pending */
178
    signal_pending = 1;
179
    return 0;
180
}
181

  
182
void force_sig(int sig)
198
/* abort execution with signal */
199
void __attribute((noreturn)) force_sig(int sig)
183 200
{
184 201
    int host_sig;
185
    /* abort execution with signal */
186 202
    host_sig = target_to_host_signal(sig);
187 203
    fprintf(stderr, "gemu: uncaught target signal %d (%s) - exiting\n", 
188 204
            sig, strsignal(host_sig));
205
#if 1
189 206
    _exit(-host_sig);
207
#else
208
    {
209
        struct sigaction act;
210
        sigemptyset(&act.sa_mask);
211
        act.sa_flags = SA_SIGINFO;
212
        act.sa_sigaction = SIG_DFL;
213
        sigaction(SIGABRT, &act, NULL);
214
        abort();
215
    }
216
#endif
190 217
}
191 218

  
192

  
193
static void host_signal_handler(int host_signum, siginfo_t *info, 
194
                                void *puc)
219
/* queue a signal so that it will be send to the virtual CPU as soon
220
   as possible */
221
int queue_signal(int sig, target_siginfo_t *info)
195 222
{
196 223
    struct emulated_sigaction *k;
197
    int sig;
224
    struct sigqueue *q, **pq;
198 225
    target_ulong handler;
199 226

  
200
    /* get target signal number */
201
    sig = host_to_target_signal(host_signum);
202
    if (sig < 1 || sig > TARGET_NSIG)
203
        return;
204
    k = &sigact_table[sig - 1];
205
#ifdef DEBUG_SIGNAL
206
    fprintf(stderr, "gemu: got signal %d\n", sig);
227
#if defined(DEBUG_SIGNAL)
228
    fprintf(stderr, "queue_sigal: sig=%d\n", 
229
            sig);
207 230
#endif
231
    k = &sigact_table[sig - 1];
208 232
    handler = k->sa._sa_handler;
209 233
    if (handler == TARGET_SIG_DFL) {
210 234
        /* default handler : ignore some signal. The other are fatal */
......
212 236
            sig != TARGET_SIGURG && 
213 237
            sig != TARGET_SIGWINCH) {
214 238
            force_sig(sig);
239
        } else {
240
            return 0; /* indicate ignored */
215 241
        }
216 242
    } else if (handler == TARGET_SIG_IGN) {
217 243
        /* ignore signal */
244
        return 0;
218 245
    } else if (handler == TARGET_SIG_ERR) {
219 246
        force_sig(sig);
220 247
    } else {
221
        queue_signal(k, sig, info);
248
        pq = &k->first;
249
        if (sig < TARGET_SIGRTMIN) {
250
            /* if non real time signal, we queue exactly one signal */
251
            if (!k->pending)
252
                q = &k->info;
253
            else
254
                return 0;
255
        } else {
256
            if (!k->pending) {
257
                /* first signal */
258
                q = &k->info;
259
            } else {
260
                q = alloc_sigqueue();
261
                if (!q)
262
                    return -EAGAIN;
263
                while (*pq != NULL)
264
                    pq = &(*pq)->next;
265
            }
266
        }
267
        *pq = q;
268
        q->info = *info;
269
        q->next = NULL;
270
        k->pending = 1;
271
        /* signal that a new signal is pending */
272
        signal_pending = 1;
273
        return 1; /* indicates that the signal was queued */
274
    }
275
}
276

  
277
#if defined(DEBUG_SIGNAL)
278
#ifdef __i386__
279
static void dump_regs(struct ucontext *uc)
280
{
281
    fprintf(stderr, 
282
            "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
283
            "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
284
            "EFL=%08x EIP=%08x\n",
285
            uc->uc_mcontext.gregs[EAX],
286
            uc->uc_mcontext.gregs[EBX],
287
            uc->uc_mcontext.gregs[ECX],
288
            uc->uc_mcontext.gregs[EDX],
289
            uc->uc_mcontext.gregs[ESI],
290
            uc->uc_mcontext.gregs[EDI],
291
            uc->uc_mcontext.gregs[EBP],
292
            uc->uc_mcontext.gregs[ESP],
293
            uc->uc_mcontext.gregs[EFL],
294
            uc->uc_mcontext.gregs[EIP]);
295
}
296
#else
297
static void dump_regs(struct ucontext *uc)
298
{
299
}
300
#endif
301

  
302
#endif
303

  
304
static void host_signal_handler(int host_signum, siginfo_t *info, 
305
                                void *puc)
306
{
307
    int sig;
308
    target_siginfo_t tinfo;
309

  
310
    /* the CPU emulator uses some host signals to detect exceptions,
311
       we we forward to it some signals */
312
    if (host_signum == SIGSEGV || host_signum == SIGBUS) {
313
        if (cpu_x86_signal_handler(host_signum, info, puc))
314
            return;
315
    }
316

  
317
    /* get target signal number */
318
    sig = host_to_target_signal(host_signum);
319
    if (sig < 1 || sig > TARGET_NSIG)
320
        return;
321
#if defined(DEBUG_SIGNAL)
322
    fprintf(stderr, "gemu: got signal %d\n", sig);
323
    dump_regs(puc);
324
#endif
325
    host_to_target_siginfo_noswap(&tinfo, info);
326
    if (queue_signal(sig, &tinfo) == 1) {
327
        /* interrupt the virtual CPU as soon as possible */
328
        cpu_x86_interrupt(global_env);
222 329
    }
223 330
}
224 331

  
......
388 495
    0;\
389 496
})
390 497

  
391
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, siginfo_t *info)
498
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, 
499
                                       const target_siginfo_t *info)
392 500
{
393
    host_to_target_siginfo(tinfo, info);
501
    tswap_siginfo(tinfo, info);
394 502
    return 0;
395 503
}
396 504

  
......
531 639
	force_sig(TARGET_SIGSEGV /* , current */);
532 640
}
533 641

  
534
static void setup_rt_frame(int sig, struct emulated_sigaction *ka, siginfo_t *info,
642
static void setup_rt_frame(int sig, struct emulated_sigaction *ka, 
643
                           target_siginfo_t *info,
535 644
			   target_sigset_t *set, CPUX86State *env)
536 645
{
537 646
	struct rt_sigframe *frame;
......
734 843
{
735 844
    int sig;
736 845
    target_ulong handler;
737
    target_sigset_t set;
846
    sigset_t set, old_set;
847
    target_sigset_t target_old_set;
738 848
    struct emulated_sigaction *k;
739 849
    struct sigqueue *q;
740 850
    
......
774 884
    } else if (handler == TARGET_SIG_ERR) {
775 885
        force_sig(sig);
776 886
    } else {
777
        set = k->sa.sa_mask;
778
        /* send the signal to the CPU */
887
        /* compute the blocked signals during the handler execution */
888
        target_to_host_sigset(&set, &k->sa.sa_mask);
889
        /* SA_NODEFER indicates that the current signal should not be
890
           blocked during the handler */
891
        if (!(k->sa.sa_flags & TARGET_SA_NODEFER))
892
            sigaddset(&set, target_to_host_signal(sig));
893
        
894
        /* block signals in the handler using Linux */
895
        sigprocmask(SIG_BLOCK, &set, &old_set);
896
        /* save the previous blocked signal state to restore it at the
897
           end of the signal execution (see do_sigreturn) */
898
        host_to_target_sigset(&target_old_set, &old_set);
899

  
900
        /* prepare the stack frame of the virtual CPU */
779 901
        if (k->sa.sa_flags & TARGET_SA_SIGINFO)
780
            setup_rt_frame(sig, k, &q->info, &set, cpu_env);
902
            setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env);
781 903
        else
782
            setup_frame(sig, k, &set, cpu_env);
904
            setup_frame(sig, k, &target_old_set, cpu_env);
783 905
	if (k->sa.sa_flags & TARGET_SA_RESETHAND)
784 906
            k->sa._sa_handler = TARGET_SIG_DFL;
785 907
    }

Also available in: Unified diff