Revision 43fff238 linux-user/signal.c
b/linux-user/signal.c | ||
---|---|---|
364 | 364 |
return 0; |
365 | 365 |
} |
366 | 366 |
|
367 |
#define __put_user(x,ptr)\ |
|
368 |
({\ |
|
369 |
int size = sizeof(*ptr);\ |
|
370 |
switch(size) {\ |
|
371 |
case 1:\ |
|
372 |
stb(ptr, (typeof(*ptr))(x));\ |
|
373 |
break;\ |
|
374 |
case 2:\ |
|
375 |
stw(ptr, (typeof(*ptr))(x));\ |
|
376 |
break;\ |
|
377 |
case 4:\ |
|
378 |
stl(ptr, (typeof(*ptr))(x));\ |
|
379 |
break;\ |
|
380 |
case 8:\ |
|
381 |
stq(ptr, (typeof(*ptr))(x));\ |
|
382 |
break;\ |
|
383 |
default:\ |
|
384 |
abort();\ |
|
385 |
}\ |
|
386 |
0;\ |
|
387 |
}) |
|
388 |
|
|
389 |
#define __get_user(x, ptr) \ |
|
390 |
({\ |
|
391 |
int size = sizeof(*ptr);\ |
|
392 |
switch(size) {\ |
|
393 |
case 1:\ |
|
394 |
x = (typeof(*ptr))ldub(ptr);\ |
|
395 |
break;\ |
|
396 |
case 2:\ |
|
397 |
x = (typeof(*ptr))lduw(ptr);\ |
|
398 |
break;\ |
|
399 |
case 4:\ |
|
400 |
x = (typeof(*ptr))ldl(ptr);\ |
|
401 |
break;\ |
|
402 |
case 8:\ |
|
403 |
x = (typeof(*ptr))ldq(ptr);\ |
|
404 |
break;\ |
|
405 |
default:\ |
|
406 |
abort();\ |
|
407 |
}\ |
|
408 |
0;\ |
|
409 |
}) |
|
410 |
|
|
411 |
|
|
412 |
#define __copy_to_user(dst, src, size)\ |
|
413 |
({\ |
|
414 |
memcpy(dst, src, size);\ |
|
415 |
0;\ |
|
416 |
}) |
|
417 |
|
|
418 |
#define __copy_from_user(dst, src, size)\ |
|
419 |
({\ |
|
420 |
memcpy(dst, src, size);\ |
|
421 |
0;\ |
|
422 |
}) |
|
423 |
|
|
424 |
#define __clear_user(dst, size)\ |
|
425 |
({\ |
|
426 |
memset(dst, 0, size);\ |
|
427 |
0;\ |
|
428 |
}) |
|
429 |
|
|
430 |
#ifndef offsetof |
|
431 |
#define offsetof(type, field) ((size_t) &((type *)0)->field) |
|
432 |
#endif |
|
433 |
|
|
434 |
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, |
|
435 |
const target_siginfo_t *info) |
|
436 |
{ |
|
437 |
tswap_siginfo(tinfo, info); |
|
438 |
return 0; |
|
439 |
} |
|
440 |
|
|
367 | 441 |
#ifdef TARGET_I386 |
368 | 442 |
|
369 | 443 |
/* from the Linux kernel */ |
... | ... | |
472 | 546 |
* Set up a signal frame. |
473 | 547 |
*/ |
474 | 548 |
|
475 |
#define __put_user(x,ptr)\ |
|
476 |
({\ |
|
477 |
int size = sizeof(*ptr);\ |
|
478 |
switch(size) {\ |
|
479 |
case 1:\ |
|
480 |
stb(ptr, (typeof(*ptr))(x));\ |
|
481 |
break;\ |
|
482 |
case 2:\ |
|
483 |
stw(ptr, (typeof(*ptr))(x));\ |
|
484 |
break;\ |
|
485 |
case 4:\ |
|
486 |
stl(ptr, (typeof(*ptr))(x));\ |
|
487 |
break;\ |
|
488 |
case 8:\ |
|
489 |
stq(ptr, (typeof(*ptr))(x));\ |
|
490 |
break;\ |
|
491 |
default:\ |
|
492 |
abort();\ |
|
493 |
}\ |
|
494 |
0;\ |
|
495 |
}) |
|
496 |
|
|
497 |
#define get_user(val, ptr) (typeof(*ptr))(*(ptr)) |
|
498 |
|
|
499 |
|
|
500 |
#define __copy_to_user(dst, src, size)\ |
|
501 |
({\ |
|
502 |
memcpy(dst, src, size);\ |
|
503 |
0;\ |
|
504 |
}) |
|
505 |
|
|
506 |
static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, |
|
507 |
const target_siginfo_t *info) |
|
508 |
{ |
|
509 |
tswap_siginfo(tinfo, info); |
|
510 |
return 0; |
|
511 |
} |
|
512 |
|
|
513 | 549 |
/* XXX: save x87 state */ |
514 | 550 |
static int |
515 | 551 |
setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate, |
... | ... | |
825 | 861 |
return 0; |
826 | 862 |
} |
827 | 863 |
|
864 |
#elif defined(TARGET_ARM) |
|
865 |
|
|
866 |
struct target_sigcontext { |
|
867 |
target_ulong trap_no; |
|
868 |
target_ulong error_code; |
|
869 |
target_ulong oldmask; |
|
870 |
target_ulong arm_r0; |
|
871 |
target_ulong arm_r1; |
|
872 |
target_ulong arm_r2; |
|
873 |
target_ulong arm_r3; |
|
874 |
target_ulong arm_r4; |
|
875 |
target_ulong arm_r5; |
|
876 |
target_ulong arm_r6; |
|
877 |
target_ulong arm_r7; |
|
878 |
target_ulong arm_r8; |
|
879 |
target_ulong arm_r9; |
|
880 |
target_ulong arm_r10; |
|
881 |
target_ulong arm_fp; |
|
882 |
target_ulong arm_ip; |
|
883 |
target_ulong arm_sp; |
|
884 |
target_ulong arm_lr; |
|
885 |
target_ulong arm_pc; |
|
886 |
target_ulong arm_cpsr; |
|
887 |
target_ulong fault_address; |
|
888 |
}; |
|
889 |
|
|
890 |
typedef struct target_sigaltstack { |
|
891 |
target_ulong ss_sp; |
|
892 |
int ss_flags; |
|
893 |
target_ulong ss_size; |
|
894 |
} target_stack_t; |
|
895 |
|
|
896 |
struct target_ucontext { |
|
897 |
target_ulong uc_flags; |
|
898 |
target_ulong uc_link; |
|
899 |
target_stack_t uc_stack; |
|
900 |
struct target_sigcontext uc_mcontext; |
|
901 |
target_sigset_t uc_sigmask; /* mask last for extensibility */ |
|
902 |
}; |
|
903 |
|
|
904 |
struct sigframe |
|
905 |
{ |
|
906 |
struct target_sigcontext sc; |
|
907 |
target_ulong extramask[TARGET_NSIG_WORDS-1]; |
|
908 |
target_ulong retcode; |
|
909 |
}; |
|
910 |
|
|
911 |
struct rt_sigframe |
|
912 |
{ |
|
913 |
struct target_siginfo *pinfo; |
|
914 |
void *puc; |
|
915 |
struct target_siginfo info; |
|
916 |
struct target_ucontext uc; |
|
917 |
target_ulong retcode; |
|
918 |
}; |
|
919 |
|
|
920 |
#define TARGET_CONFIG_CPU_32 1 |
|
921 |
|
|
922 |
/* |
|
923 |
* For ARM syscalls, we encode the syscall number into the instruction. |
|
924 |
*/ |
|
925 |
#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE)) |
|
926 |
#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE)) |
|
927 |
|
|
928 |
/* |
|
929 |
* For Thumb syscalls, we pass the syscall number via r7. We therefore |
|
930 |
* need two 16-bit instructions. |
|
931 |
*/ |
|
932 |
#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn)) |
|
933 |
#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn)) |
|
934 |
|
|
935 |
static const target_ulong retcodes[4] = { |
|
936 |
SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN, |
|
937 |
SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN |
|
938 |
}; |
|
939 |
|
|
940 |
|
|
941 |
#define __put_user_error(x,p,e) __put_user(x, p) |
|
942 |
#define __get_user_error(x,p,e) __get_user(x, p) |
|
943 |
|
|
944 |
static inline int valid_user_regs(CPUState *regs) |
|
945 |
{ |
|
946 |
return 1; |
|
947 |
} |
|
948 |
|
|
949 |
static int |
|
950 |
setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ |
|
951 |
CPUState *env, unsigned long mask) |
|
952 |
{ |
|
953 |
int err = 0; |
|
954 |
|
|
955 |
__put_user_error(env->regs[0], &sc->arm_r0, err); |
|
956 |
__put_user_error(env->regs[1], &sc->arm_r1, err); |
|
957 |
__put_user_error(env->regs[2], &sc->arm_r2, err); |
|
958 |
__put_user_error(env->regs[3], &sc->arm_r3, err); |
|
959 |
__put_user_error(env->regs[4], &sc->arm_r4, err); |
|
960 |
__put_user_error(env->regs[5], &sc->arm_r5, err); |
|
961 |
__put_user_error(env->regs[6], &sc->arm_r6, err); |
|
962 |
__put_user_error(env->regs[7], &sc->arm_r7, err); |
|
963 |
__put_user_error(env->regs[8], &sc->arm_r8, err); |
|
964 |
__put_user_error(env->regs[9], &sc->arm_r9, err); |
|
965 |
__put_user_error(env->regs[10], &sc->arm_r10, err); |
|
966 |
__put_user_error(env->regs[11], &sc->arm_fp, err); |
|
967 |
__put_user_error(env->regs[12], &sc->arm_ip, err); |
|
968 |
__put_user_error(env->regs[13], &sc->arm_sp, err); |
|
969 |
__put_user_error(env->regs[14], &sc->arm_lr, err); |
|
970 |
__put_user_error(env->regs[15], &sc->arm_pc, err); |
|
971 |
#ifdef TARGET_CONFIG_CPU_32 |
|
972 |
__put_user_error(env->cpsr, &sc->arm_cpsr, err); |
|
973 |
#endif |
|
974 |
|
|
975 |
__put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err); |
|
976 |
__put_user_error(/* current->thread.error_code */ 0, &sc->error_code, err); |
|
977 |
__put_user_error(/* current->thread.address */ 0, &sc->fault_address, err); |
|
978 |
__put_user_error(mask, &sc->oldmask, err); |
|
979 |
|
|
980 |
return err; |
|
981 |
} |
|
982 |
|
|
983 |
static inline void * |
|
984 |
get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize) |
|
985 |
{ |
|
986 |
unsigned long sp = regs->regs[13]; |
|
987 |
|
|
988 |
#if 0 |
|
989 |
/* |
|
990 |
* This is the X/Open sanctioned signal stack switching. |
|
991 |
*/ |
|
992 |
if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) |
|
993 |
sp = current->sas_ss_sp + current->sas_ss_size; |
|
994 |
#endif |
|
995 |
/* |
|
996 |
* ATPCS B01 mandates 8-byte alignment |
|
997 |
*/ |
|
998 |
return (void *)((sp - framesize) & ~7); |
|
999 |
} |
|
1000 |
|
|
1001 |
static int |
|
1002 |
setup_return(CPUState *env, struct emulated_sigaction *ka, |
|
1003 |
target_ulong *rc, void *frame, int usig) |
|
1004 |
{ |
|
1005 |
target_ulong handler = (target_ulong)ka->sa._sa_handler; |
|
1006 |
target_ulong retcode; |
|
1007 |
int thumb = 0; |
|
1008 |
#if defined(TARGET_CONFIG_CPU_32) |
|
1009 |
target_ulong cpsr = env->cpsr; |
|
1010 |
|
|
1011 |
#if 0 |
|
1012 |
/* |
|
1013 |
* Maybe we need to deliver a 32-bit signal to a 26-bit task. |
|
1014 |
*/ |
|
1015 |
if (ka->sa.sa_flags & SA_THIRTYTWO) |
|
1016 |
cpsr = (cpsr & ~MODE_MASK) | USR_MODE; |
|
1017 |
|
|
1018 |
#ifdef CONFIG_ARM_THUMB |
|
1019 |
if (elf_hwcap & HWCAP_THUMB) { |
|
1020 |
/* |
|
1021 |
* The LSB of the handler determines if we're going to |
|
1022 |
* be using THUMB or ARM mode for this signal handler. |
|
1023 |
*/ |
|
1024 |
thumb = handler & 1; |
|
1025 |
|
|
1026 |
if (thumb) |
|
1027 |
cpsr |= T_BIT; |
|
1028 |
else |
|
1029 |
cpsr &= ~T_BIT; |
|
1030 |
} |
|
1031 |
#endif |
|
1032 |
#endif |
|
1033 |
#endif /* TARGET_CONFIG_CPU_32 */ |
|
1034 |
|
|
1035 |
if (ka->sa.sa_flags & TARGET_SA_RESTORER) { |
|
1036 |
retcode = (target_ulong)ka->sa.sa_restorer; |
|
1037 |
} else { |
|
1038 |
unsigned int idx = thumb; |
|
1039 |
|
|
1040 |
if (ka->sa.sa_flags & TARGET_SA_SIGINFO) |
|
1041 |
idx += 2; |
|
1042 |
|
|
1043 |
if (__put_user(retcodes[idx], rc)) |
|
1044 |
return 1; |
|
1045 |
#if 0 |
|
1046 |
flush_icache_range((target_ulong)rc, |
|
1047 |
(target_ulong)(rc + 1)); |
|
1048 |
#endif |
|
1049 |
retcode = ((target_ulong)rc) + thumb; |
|
1050 |
} |
|
1051 |
|
|
1052 |
env->regs[0] = usig; |
|
1053 |
env->regs[13] = (target_ulong)frame; |
|
1054 |
env->regs[14] = retcode; |
|
1055 |
env->regs[15] = handler & (thumb ? ~1 : ~3); |
|
1056 |
|
|
1057 |
#ifdef TARGET_CONFIG_CPU_32 |
|
1058 |
env->cpsr = cpsr; |
|
1059 |
#endif |
|
1060 |
|
|
1061 |
return 0; |
|
1062 |
} |
|
1063 |
|
|
1064 |
static void setup_frame(int usig, struct emulated_sigaction *ka, |
|
1065 |
target_sigset_t *set, CPUState *regs) |
|
1066 |
{ |
|
1067 |
struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame)); |
|
1068 |
int err = 0; |
|
1069 |
|
|
1070 |
err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); |
|
1071 |
|
|
1072 |
if (TARGET_NSIG_WORDS > 1) { |
|
1073 |
err |= __copy_to_user(frame->extramask, &set->sig[1], |
|
1074 |
sizeof(frame->extramask)); |
|
1075 |
} |
|
1076 |
|
|
1077 |
if (err == 0) |
|
1078 |
err = setup_return(regs, ka, &frame->retcode, frame, usig); |
|
1079 |
// return err; |
|
1080 |
} |
|
1081 |
|
|
1082 |
static void setup_rt_frame(int usig, struct emulated_sigaction *ka, |
|
1083 |
target_siginfo_t *info, |
|
1084 |
target_sigset_t *set, CPUState *env) |
|
1085 |
{ |
|
1086 |
struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame)); |
|
1087 |
int err = 0; |
|
1088 |
|
|
1089 |
#if 0 |
|
1090 |
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) |
|
1091 |
return 1; |
|
1092 |
#endif |
|
1093 |
__put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err); |
|
1094 |
__put_user_error(&frame->uc, (target_ulong *)&frame->puc, err); |
|
1095 |
err |= copy_siginfo_to_user(&frame->info, info); |
|
1096 |
|
|
1097 |
/* Clear all the bits of the ucontext we don't use. */ |
|
1098 |
err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); |
|
1099 |
|
|
1100 |
err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/ |
|
1101 |
env, set->sig[0]); |
|
1102 |
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
|
1103 |
|
|
1104 |
if (err == 0) |
|
1105 |
err = setup_return(env, ka, &frame->retcode, frame, usig); |
|
1106 |
|
|
1107 |
if (err == 0) { |
|
1108 |
/* |
|
1109 |
* For realtime signals we must also set the second and third |
|
1110 |
* arguments for the signal handler. |
|
1111 |
* -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06 |
|
1112 |
*/ |
|
1113 |
env->regs[1] = (target_ulong)frame->pinfo; |
|
1114 |
env->regs[2] = (target_ulong)frame->puc; |
|
1115 |
} |
|
1116 |
|
|
1117 |
// return err; |
|
1118 |
} |
|
1119 |
|
|
1120 |
static int |
|
1121 |
restore_sigcontext(CPUState *env, struct target_sigcontext *sc) |
|
1122 |
{ |
|
1123 |
int err = 0; |
|
1124 |
|
|
1125 |
__get_user_error(env->regs[0], &sc->arm_r0, err); |
|
1126 |
__get_user_error(env->regs[1], &sc->arm_r1, err); |
|
1127 |
__get_user_error(env->regs[2], &sc->arm_r2, err); |
|
1128 |
__get_user_error(env->regs[3], &sc->arm_r3, err); |
|
1129 |
__get_user_error(env->regs[4], &sc->arm_r4, err); |
|
1130 |
__get_user_error(env->regs[5], &sc->arm_r5, err); |
|
1131 |
__get_user_error(env->regs[6], &sc->arm_r6, err); |
|
1132 |
__get_user_error(env->regs[7], &sc->arm_r7, err); |
|
1133 |
__get_user_error(env->regs[8], &sc->arm_r8, err); |
|
1134 |
__get_user_error(env->regs[9], &sc->arm_r9, err); |
|
1135 |
__get_user_error(env->regs[10], &sc->arm_r10, err); |
|
1136 |
__get_user_error(env->regs[11], &sc->arm_fp, err); |
|
1137 |
__get_user_error(env->regs[12], &sc->arm_ip, err); |
|
1138 |
__get_user_error(env->regs[13], &sc->arm_sp, err); |
|
1139 |
__get_user_error(env->regs[14], &sc->arm_lr, err); |
|
1140 |
__get_user_error(env->regs[15], &sc->arm_pc, err); |
|
1141 |
#ifdef TARGET_CONFIG_CPU_32 |
|
1142 |
__get_user_error(env->cpsr, &sc->arm_cpsr, err); |
|
1143 |
#endif |
|
1144 |
|
|
1145 |
err |= !valid_user_regs(env); |
|
1146 |
|
|
1147 |
return err; |
|
1148 |
} |
|
1149 |
|
|
1150 |
long do_sigreturn(CPUState *env) |
|
1151 |
{ |
|
1152 |
struct sigframe *frame; |
|
1153 |
target_sigset_t set; |
|
1154 |
sigset_t host_set; |
|
1155 |
|
|
1156 |
/* |
|
1157 |
* Since we stacked the signal on a 64-bit boundary, |
|
1158 |
* then 'sp' should be word aligned here. If it's |
|
1159 |
* not, then the user is trying to mess with us. |
|
1160 |
*/ |
|
1161 |
if (env->regs[13] & 7) |
|
1162 |
goto badframe; |
|
1163 |
|
|
1164 |
frame = (struct sigframe *)env->regs[13]; |
|
1165 |
|
|
1166 |
#if 0 |
|
1167 |
if (verify_area(VERIFY_READ, frame, sizeof (*frame))) |
|
1168 |
goto badframe; |
|
1169 |
#endif |
|
1170 |
if (__get_user(set.sig[0], &frame->sc.oldmask) |
|
1171 |
|| (TARGET_NSIG_WORDS > 1 |
|
1172 |
&& __copy_from_user(&set.sig[1], &frame->extramask, |
|
1173 |
sizeof(frame->extramask)))) |
|
1174 |
goto badframe; |
|
1175 |
|
|
1176 |
target_to_host_sigset(&host_set, &set); |
|
1177 |
sigprocmask(SIG_SETMASK, &host_set, NULL); |
|
1178 |
|
|
1179 |
if (restore_sigcontext(env, &frame->sc)) |
|
1180 |
goto badframe; |
|
1181 |
|
|
1182 |
#if 0 |
|
1183 |
/* Send SIGTRAP if we're single-stepping */ |
|
1184 |
if (ptrace_cancel_bpt(current)) |
|
1185 |
send_sig(SIGTRAP, current, 1); |
|
1186 |
#endif |
|
1187 |
return env->regs[0]; |
|
1188 |
|
|
1189 |
badframe: |
|
1190 |
force_sig(SIGSEGV /* , current */); |
|
1191 |
return 0; |
|
1192 |
} |
|
1193 |
|
|
1194 |
long do_rt_sigreturn(CPUState *env) |
|
1195 |
{ |
|
1196 |
struct rt_sigframe *frame; |
|
1197 |
target_sigset_t set; |
|
1198 |
sigset_t host_set; |
|
1199 |
|
|
1200 |
/* |
|
1201 |
* Since we stacked the signal on a 64-bit boundary, |
|
1202 |
* then 'sp' should be word aligned here. If it's |
|
1203 |
* not, then the user is trying to mess with us. |
|
1204 |
*/ |
|
1205 |
if (env->regs[13] & 7) |
|
1206 |
goto badframe; |
|
1207 |
|
|
1208 |
frame = (struct rt_sigframe *)env->regs[13]; |
|
1209 |
|
|
1210 |
#if 0 |
|
1211 |
if (verify_area(VERIFY_READ, frame, sizeof (*frame))) |
|
1212 |
goto badframe; |
|
1213 |
#endif |
|
1214 |
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) |
|
1215 |
goto badframe; |
|
1216 |
|
|
1217 |
target_to_host_sigset(&host_set, &set); |
|
1218 |
sigprocmask(SIG_SETMASK, &host_set, NULL); |
|
1219 |
|
|
1220 |
if (restore_sigcontext(env, &frame->uc.uc_mcontext)) |
|
1221 |
goto badframe; |
|
1222 |
|
|
1223 |
#if 0 |
|
1224 |
/* Send SIGTRAP if we're single-stepping */ |
|
1225 |
if (ptrace_cancel_bpt(current)) |
|
1226 |
send_sig(SIGTRAP, current, 1); |
|
1227 |
#endif |
|
1228 |
return env->regs[0]; |
|
1229 |
|
|
1230 |
badframe: |
|
1231 |
force_sig(SIGSEGV /* , current */); |
|
1232 |
return 0; |
|
1233 |
} |
|
1234 |
|
|
828 | 1235 |
#else |
829 | 1236 |
|
830 | 1237 |
static void setup_frame(int sig, struct emulated_sigaction *ka, |
Also available in: Unified diff