Commit a8c3320434cc0a7e8eaf3d58b56194f37d7441d3
1 parent
1ffc346f
Update ARM non-rt sigframe layout.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4385 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
165 additions
and
101 deletions
linux-user/signal.c
... | ... | @@ -1038,13 +1038,19 @@ struct target_ucontext_v2 { |
1038 | 1038 | abi_ulong tuc_regspace[128] __attribute__((__aligned__(8))); |
1039 | 1039 | }; |
1040 | 1040 | |
1041 | -struct sigframe | |
1041 | +struct sigframe_v1 | |
1042 | 1042 | { |
1043 | 1043 | struct target_sigcontext sc; |
1044 | 1044 | abi_ulong extramask[TARGET_NSIG_WORDS-1]; |
1045 | 1045 | abi_ulong retcode; |
1046 | 1046 | }; |
1047 | 1047 | |
1048 | +struct sigframe_v2 | |
1049 | +{ | |
1050 | + struct target_ucontext_v2 uc; | |
1051 | + abi_ulong retcode; | |
1052 | +}; | |
1053 | + | |
1048 | 1054 | struct rt_sigframe_v1 |
1049 | 1055 | { |
1050 | 1056 | abi_ulong pinfo; |
... | ... | @@ -1082,7 +1088,6 @@ static const abi_ulong retcodes[4] = { |
1082 | 1088 | }; |
1083 | 1089 | |
1084 | 1090 | |
1085 | -#define __put_user_error(x,p,e) __put_user(x, p) | |
1086 | 1091 | #define __get_user_error(x,p,e) __get_user(x, p) |
1087 | 1092 | |
1088 | 1093 | static inline int valid_user_regs(CPUState *regs) |
... | ... | @@ -1090,38 +1095,34 @@ static inline int valid_user_regs(CPUState *regs) |
1090 | 1095 | return 1; |
1091 | 1096 | } |
1092 | 1097 | |
1093 | -static int | |
1098 | +static void | |
1094 | 1099 | setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/ |
1095 | 1100 | CPUState *env, abi_ulong mask) |
1096 | 1101 | { |
1097 | - int err = 0; | |
1098 | - | |
1099 | - __put_user_error(env->regs[0], &sc->arm_r0, err); | |
1100 | - __put_user_error(env->regs[1], &sc->arm_r1, err); | |
1101 | - __put_user_error(env->regs[2], &sc->arm_r2, err); | |
1102 | - __put_user_error(env->regs[3], &sc->arm_r3, err); | |
1103 | - __put_user_error(env->regs[4], &sc->arm_r4, err); | |
1104 | - __put_user_error(env->regs[5], &sc->arm_r5, err); | |
1105 | - __put_user_error(env->regs[6], &sc->arm_r6, err); | |
1106 | - __put_user_error(env->regs[7], &sc->arm_r7, err); | |
1107 | - __put_user_error(env->regs[8], &sc->arm_r8, err); | |
1108 | - __put_user_error(env->regs[9], &sc->arm_r9, err); | |
1109 | - __put_user_error(env->regs[10], &sc->arm_r10, err); | |
1110 | - __put_user_error(env->regs[11], &sc->arm_fp, err); | |
1111 | - __put_user_error(env->regs[12], &sc->arm_ip, err); | |
1112 | - __put_user_error(env->regs[13], &sc->arm_sp, err); | |
1113 | - __put_user_error(env->regs[14], &sc->arm_lr, err); | |
1114 | - __put_user_error(env->regs[15], &sc->arm_pc, err); | |
1102 | + __put_user(env->regs[0], &sc->arm_r0); | |
1103 | + __put_user(env->regs[1], &sc->arm_r1); | |
1104 | + __put_user(env->regs[2], &sc->arm_r2); | |
1105 | + __put_user(env->regs[3], &sc->arm_r3); | |
1106 | + __put_user(env->regs[4], &sc->arm_r4); | |
1107 | + __put_user(env->regs[5], &sc->arm_r5); | |
1108 | + __put_user(env->regs[6], &sc->arm_r6); | |
1109 | + __put_user(env->regs[7], &sc->arm_r7); | |
1110 | + __put_user(env->regs[8], &sc->arm_r8); | |
1111 | + __put_user(env->regs[9], &sc->arm_r9); | |
1112 | + __put_user(env->regs[10], &sc->arm_r10); | |
1113 | + __put_user(env->regs[11], &sc->arm_fp); | |
1114 | + __put_user(env->regs[12], &sc->arm_ip); | |
1115 | + __put_user(env->regs[13], &sc->arm_sp); | |
1116 | + __put_user(env->regs[14], &sc->arm_lr); | |
1117 | + __put_user(env->regs[15], &sc->arm_pc); | |
1115 | 1118 | #ifdef TARGET_CONFIG_CPU_32 |
1116 | - __put_user_error(cpsr_read(env), &sc->arm_cpsr, err); | |
1119 | + __put_user(cpsr_read(env), &sc->arm_cpsr); | |
1117 | 1120 | #endif |
1118 | 1121 | |
1119 | - __put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err); | |
1120 | - __put_user_error(/* current->thread.error_code */ 0, &sc->error_code, err); | |
1121 | - __put_user_error(/* current->thread.address */ 0, &sc->fault_address, err); | |
1122 | - __put_user_error(mask, &sc->oldmask, err); | |
1123 | - | |
1124 | - return err; | |
1122 | + __put_user(/* current->thread.trap_no */ 0, &sc->trap_no); | |
1123 | + __put_user(/* current->thread.error_code */ 0, &sc->error_code); | |
1124 | + __put_user(/* current->thread.address */ 0, &sc->fault_address); | |
1125 | + __put_user(mask, &sc->oldmask); | |
1125 | 1126 | } |
1126 | 1127 | |
1127 | 1128 | static inline abi_ulong |
... | ... | @@ -1180,31 +1181,78 @@ setup_return(CPUState *env, struct emulated_sigaction *ka, |
1180 | 1181 | return 0; |
1181 | 1182 | } |
1182 | 1183 | |
1184 | +static void setup_sigframe_v2(struct target_ucontext_v2 *uc, | |
1185 | + target_sigset_t *set, CPUState *env) | |
1186 | +{ | |
1187 | + struct target_sigaltstack stack; | |
1188 | + int i; | |
1189 | + | |
1190 | + /* Clear all the bits of the ucontext we don't use. */ | |
1191 | + memset(uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext)); | |
1192 | + | |
1193 | + memset(&stack, 0, sizeof(stack)); | |
1194 | + __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); | |
1195 | + __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); | |
1196 | + __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); | |
1197 | + memcpy(&uc->tuc_stack, &stack, sizeof(stack)); | |
1198 | + | |
1199 | + setup_sigcontext(&uc->tuc_mcontext, env, set->sig[0]); | |
1200 | + /* FIXME: Save coprocessor signal frame. */ | |
1201 | + for(i = 0; i < TARGET_NSIG_WORDS; i++) { | |
1202 | + __put_user(set->sig[i], &uc->tuc_sigmask.sig[i]); | |
1203 | + } | |
1204 | +} | |
1205 | + | |
1183 | 1206 | /* compare linux/arch/arm/kernel/signal.c:setup_frame() */ |
1184 | -static void setup_frame(int usig, struct emulated_sigaction *ka, | |
1185 | - target_sigset_t *set, CPUState *regs) | |
1207 | +static void setup_frame_v1(int usig, struct emulated_sigaction *ka, | |
1208 | + target_sigset_t *set, CPUState *regs) | |
1186 | 1209 | { |
1187 | - struct sigframe *frame; | |
1210 | + struct sigframe_v1 *frame; | |
1188 | 1211 | abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); |
1189 | - int i, err = 0; | |
1212 | + int i; | |
1190 | 1213 | |
1191 | 1214 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
1192 | 1215 | return; |
1193 | 1216 | |
1194 | - err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); | |
1217 | + setup_sigcontext(&frame->sc, regs, set->sig[0]); | |
1195 | 1218 | |
1196 | 1219 | for(i = 1; i < TARGET_NSIG_WORDS; i++) { |
1197 | 1220 | if (__put_user(set->sig[i], &frame->extramask[i - 1])) |
1198 | 1221 | goto end; |
1199 | 1222 | } |
1200 | 1223 | |
1201 | - if (err == 0) | |
1202 | - err = setup_return(regs, ka, &frame->retcode, frame_addr, usig, | |
1203 | - frame_addr + offsetof(struct sigframe, retcode)); | |
1224 | + setup_return(regs, ka, &frame->retcode, frame_addr, usig, | |
1225 | + frame_addr + offsetof(struct sigframe_v1, retcode)); | |
1204 | 1226 | |
1205 | 1227 | end: |
1206 | 1228 | unlock_user_struct(frame, frame_addr, 1); |
1207 | - // return err; | |
1229 | +} | |
1230 | + | |
1231 | +static void setup_frame_v2(int usig, struct emulated_sigaction *ka, | |
1232 | + target_sigset_t *set, CPUState *regs) | |
1233 | +{ | |
1234 | + struct sigframe_v2 *frame; | |
1235 | + abi_ulong frame_addr = get_sigframe(ka, regs, sizeof(*frame)); | |
1236 | + | |
1237 | + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) | |
1238 | + return; | |
1239 | + | |
1240 | + setup_sigframe_v2(&frame->uc, set, regs); | |
1241 | + | |
1242 | + setup_return(regs, ka, &frame->retcode, frame_addr, usig, | |
1243 | + frame_addr + offsetof(struct sigframe_v2, retcode)); | |
1244 | + | |
1245 | + unlock_user_struct(frame, frame_addr, 1); | |
1246 | +} | |
1247 | + | |
1248 | +static void setup_frame(int usig, struct emulated_sigaction *ka, | |
1249 | + target_sigset_t *set, CPUState *regs) | |
1250 | +{ | |
1251 | + if (get_osversion() >= 0x020612) { | |
1252 | + setup_frame_v2(usig, ka, set, regs); | |
1253 | + } else { | |
1254 | + setup_frame_v1(usig, ka, set, regs); | |
1255 | + } | |
1208 | 1256 | } |
1209 | 1257 | |
1210 | 1258 | /* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */ |
... | ... | @@ -1215,17 +1263,17 @@ static void setup_rt_frame_v1(int usig, struct emulated_sigaction *ka, |
1215 | 1263 | struct rt_sigframe_v1 *frame; |
1216 | 1264 | abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); |
1217 | 1265 | struct target_sigaltstack stack; |
1218 | - int i, err = 0; | |
1266 | + int i; | |
1219 | 1267 | abi_ulong info_addr, uc_addr; |
1220 | 1268 | |
1221 | 1269 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
1222 | 1270 | return /* 1 */; |
1223 | 1271 | |
1224 | 1272 | info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info); |
1225 | - __put_user_error(info_addr, &frame->pinfo, err); | |
1273 | + __put_user(info_addr, &frame->pinfo); | |
1226 | 1274 | uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc); |
1227 | - __put_user_error(uc_addr, &frame->puc, err); | |
1228 | - err |= copy_siginfo_to_user(&frame->info, info); | |
1275 | + __put_user(uc_addr, &frame->puc); | |
1276 | + copy_siginfo_to_user(&frame->info, info); | |
1229 | 1277 | |
1230 | 1278 | /* Clear all the bits of the ucontext we don't use. */ |
1231 | 1279 | memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext)); |
... | ... | @@ -1236,26 +1284,20 @@ static void setup_rt_frame_v1(int usig, struct emulated_sigaction *ka, |
1236 | 1284 | __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); |
1237 | 1285 | memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); |
1238 | 1286 | |
1239 | - err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ | |
1240 | - env, set->sig[0]); | |
1287 | + setup_sigcontext(&frame->uc.tuc_mcontext, env, set->sig[0]); | |
1241 | 1288 | for(i = 0; i < TARGET_NSIG_WORDS; i++) { |
1242 | 1289 | if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) |
1243 | 1290 | goto end; |
1244 | 1291 | } |
1245 | 1292 | |
1246 | - if (err == 0) | |
1247 | - err = setup_return(env, ka, &frame->retcode, frame_addr, usig, | |
1248 | - frame_addr + offsetof(struct rt_sigframe_v1, retcode)); | |
1293 | + setup_return(env, ka, &frame->retcode, frame_addr, usig, | |
1294 | + frame_addr + offsetof(struct rt_sigframe_v1, retcode)); | |
1249 | 1295 | |
1250 | - if (err == 0) { | |
1251 | - env->regs[1] = info_addr; | |
1252 | - env->regs[2] = uc_addr; | |
1253 | - } | |
1296 | + env->regs[1] = info_addr; | |
1297 | + env->regs[2] = uc_addr; | |
1254 | 1298 | |
1255 | 1299 | end: |
1256 | 1300 | unlock_user_struct(frame, frame_addr, 1); |
1257 | - | |
1258 | - // return err; | |
1259 | 1301 | } |
1260 | 1302 | |
1261 | 1303 | static void setup_rt_frame_v2(int usig, struct emulated_sigaction *ka, |
... | ... | @@ -1264,8 +1306,6 @@ static void setup_rt_frame_v2(int usig, struct emulated_sigaction *ka, |
1264 | 1306 | { |
1265 | 1307 | struct rt_sigframe_v2 *frame; |
1266 | 1308 | abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); |
1267 | - struct target_sigaltstack stack; | |
1268 | - int i, err = 0; | |
1269 | 1309 | abi_ulong info_addr, uc_addr; |
1270 | 1310 | |
1271 | 1311 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
... | ... | @@ -1273,42 +1313,17 @@ static void setup_rt_frame_v2(int usig, struct emulated_sigaction *ka, |
1273 | 1313 | |
1274 | 1314 | info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info); |
1275 | 1315 | uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc); |
1276 | - err |= copy_siginfo_to_user(&frame->info, info); | |
1316 | + copy_siginfo_to_user(&frame->info, info); | |
1277 | 1317 | |
1278 | - /* Clear all the bits of the ucontext we don't use. */ | |
1279 | - memset(&frame->uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext)); | |
1318 | + setup_sigframe_v2(&frame->uc, set, env); | |
1280 | 1319 | |
1281 | - memset(&stack, 0, sizeof(stack)); | |
1282 | - __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); | |
1283 | - __put_user(target_sigaltstack_used.ss_size, &stack.ss_size); | |
1284 | - __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags); | |
1285 | - memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack)); | |
1320 | + setup_return(env, ka, &frame->retcode, frame_addr, usig, | |
1321 | + frame_addr + offsetof(struct rt_sigframe_v2, retcode)); | |
1286 | 1322 | |
1287 | - err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/ | |
1288 | - env, set->sig[0]); | |
1289 | - for(i = 0; i < TARGET_NSIG_WORDS; i++) { | |
1290 | - if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i])) | |
1291 | - goto end; | |
1292 | - } | |
1323 | + env->regs[1] = info_addr; | |
1324 | + env->regs[2] = uc_addr; | |
1293 | 1325 | |
1294 | - if (err == 0) | |
1295 | - err = setup_return(env, ka, &frame->retcode, frame_addr, usig, | |
1296 | - frame_addr + offsetof(struct rt_sigframe_v2, retcode)); | |
1297 | - | |
1298 | - if (err == 0) { | |
1299 | - /* | |
1300 | - * For realtime signals we must also set the second and third | |
1301 | - * arguments for the signal handler. | |
1302 | - * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06 | |
1303 | - */ | |
1304 | - env->regs[1] = info_addr; | |
1305 | - env->regs[2] = uc_addr; | |
1306 | - } | |
1307 | - | |
1308 | -end: | |
1309 | 1326 | unlock_user_struct(frame, frame_addr, 1); |
1310 | - | |
1311 | - // return err; | |
1312 | 1327 | } |
1313 | 1328 | |
1314 | 1329 | static void setup_rt_frame(int usig, struct emulated_sigaction *ka, |
... | ... | @@ -1354,10 +1369,10 @@ restore_sigcontext(CPUState *env, struct target_sigcontext *sc) |
1354 | 1369 | return err; |
1355 | 1370 | } |
1356 | 1371 | |
1357 | -long do_sigreturn(CPUState *env) | |
1372 | +long do_sigreturn_v1(CPUState *env) | |
1358 | 1373 | { |
1359 | 1374 | abi_ulong frame_addr; |
1360 | - struct sigframe *frame; | |
1375 | + struct sigframe_v1 *frame; | |
1361 | 1376 | target_sigset_t set; |
1362 | 1377 | sigset_t host_set; |
1363 | 1378 | int i; |
... | ... | @@ -1401,6 +1416,67 @@ badframe: |
1401 | 1416 | return 0; |
1402 | 1417 | } |
1403 | 1418 | |
1419 | +static int do_sigframe_return_v2(CPUState *env, target_ulong frame_addr, | |
1420 | + struct target_ucontext_v2 *uc) | |
1421 | +{ | |
1422 | + sigset_t host_set; | |
1423 | + | |
1424 | + target_to_host_sigset(&host_set, &uc->tuc_sigmask); | |
1425 | + sigprocmask(SIG_SETMASK, &host_set, NULL); | |
1426 | + | |
1427 | + if (restore_sigcontext(env, &uc->tuc_mcontext)) | |
1428 | + return 1; | |
1429 | + | |
1430 | + if (do_sigaltstack(frame_addr + offsetof(struct target_ucontext_v2, tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) | |
1431 | + return 1; | |
1432 | + | |
1433 | +#if 0 | |
1434 | + /* Send SIGTRAP if we're single-stepping */ | |
1435 | + if (ptrace_cancel_bpt(current)) | |
1436 | + send_sig(SIGTRAP, current, 1); | |
1437 | +#endif | |
1438 | + | |
1439 | + return 0; | |
1440 | +} | |
1441 | + | |
1442 | +long do_sigreturn_v2(CPUState *env) | |
1443 | +{ | |
1444 | + abi_ulong frame_addr; | |
1445 | + struct sigframe_v2 *frame; | |
1446 | + | |
1447 | + /* | |
1448 | + * Since we stacked the signal on a 64-bit boundary, | |
1449 | + * then 'sp' should be word aligned here. If it's | |
1450 | + * not, then the user is trying to mess with us. | |
1451 | + */ | |
1452 | + if (env->regs[13] & 7) | |
1453 | + goto badframe; | |
1454 | + | |
1455 | + frame_addr = env->regs[13]; | |
1456 | + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) | |
1457 | + goto badframe; | |
1458 | + | |
1459 | + if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) | |
1460 | + goto badframe; | |
1461 | + | |
1462 | + unlock_user_struct(frame, frame_addr, 0); | |
1463 | + return env->regs[0]; | |
1464 | + | |
1465 | +badframe: | |
1466 | + unlock_user_struct(frame, frame_addr, 0); | |
1467 | + force_sig(SIGSEGV /* , current */); | |
1468 | + return 0; | |
1469 | +} | |
1470 | + | |
1471 | +long do_sigreturn(CPUState *env) | |
1472 | +{ | |
1473 | + if (get_osversion() >= 0x020612) { | |
1474 | + return do_sigreturn_v2(env); | |
1475 | + } else { | |
1476 | + return do_sigreturn_v1(env); | |
1477 | + } | |
1478 | +} | |
1479 | + | |
1404 | 1480 | long do_rt_sigreturn_v1(CPUState *env) |
1405 | 1481 | { |
1406 | 1482 | abi_ulong frame_addr; |
... | ... | @@ -1446,7 +1522,6 @@ long do_rt_sigreturn_v2(CPUState *env) |
1446 | 1522 | { |
1447 | 1523 | abi_ulong frame_addr; |
1448 | 1524 | struct rt_sigframe_v2 *frame; |
1449 | - sigset_t host_set; | |
1450 | 1525 | |
1451 | 1526 | /* |
1452 | 1527 | * Since we stacked the signal on a 64-bit boundary, |
... | ... | @@ -1460,20 +1535,9 @@ long do_rt_sigreturn_v2(CPUState *env) |
1460 | 1535 | if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) |
1461 | 1536 | goto badframe; |
1462 | 1537 | |
1463 | - target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask); | |
1464 | - sigprocmask(SIG_SETMASK, &host_set, NULL); | |
1465 | - | |
1466 | - if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) | |
1467 | - goto badframe; | |
1468 | - | |
1469 | - if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v2, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) | |
1470 | - goto badframe; | |
1538 | + if (do_sigframe_return_v2(env, frame_addr, &frame->uc)) | |
1539 | + goto badframe; | |
1471 | 1540 | |
1472 | -#if 0 | |
1473 | - /* Send SIGTRAP if we're single-stepping */ | |
1474 | - if (ptrace_cancel_bpt(current)) | |
1475 | - send_sig(SIGTRAP, current, 1); | |
1476 | -#endif | |
1477 | 1541 | unlock_user_struct(frame, frame_addr, 0); |
1478 | 1542 | return env->regs[0]; |
1479 | 1543 | ... | ... |