Commit a745ec6d91fc3ee06b4c281d30b472aeaa6302e0
1 parent
f0b86b14
Update ARM rt_frame layout.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4365 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
172 additions
and
14 deletions
linux-user/qemu.h
| @@ -169,6 +169,7 @@ void cpu_loop(CPUState *env); | @@ -169,6 +169,7 @@ void cpu_loop(CPUState *env); | ||
| 169 | void init_paths(const char *prefix); | 169 | void init_paths(const char *prefix); |
| 170 | const char *path(const char *pathname); | 170 | const char *path(const char *pathname); |
| 171 | char *target_strerror(int err); | 171 | char *target_strerror(int err); |
| 172 | +int get_osversion(void); | ||
| 172 | 173 | ||
| 173 | extern int loglevel; | 174 | extern int loglevel; |
| 174 | extern FILE *logfile; | 175 | extern FILE *logfile; |
linux-user/signal.c
| @@ -1020,12 +1020,22 @@ struct target_sigcontext { | @@ -1020,12 +1020,22 @@ struct target_sigcontext { | ||
| 1020 | abi_ulong fault_address; | 1020 | abi_ulong fault_address; |
| 1021 | }; | 1021 | }; |
| 1022 | 1022 | ||
| 1023 | -struct target_ucontext { | 1023 | +struct target_ucontext_v1 { |
| 1024 | + abi_ulong tuc_flags; | ||
| 1025 | + abi_ulong tuc_link; | ||
| 1026 | + target_stack_t tuc_stack; | ||
| 1027 | + struct target_sigcontext tuc_mcontext; | ||
| 1028 | + target_sigset_t tuc_sigmask; /* mask last for extensibility */ | ||
| 1029 | +}; | ||
| 1030 | + | ||
| 1031 | +struct target_ucontext_v2 { | ||
| 1024 | abi_ulong tuc_flags; | 1032 | abi_ulong tuc_flags; |
| 1025 | abi_ulong tuc_link; | 1033 | abi_ulong tuc_link; |
| 1026 | target_stack_t tuc_stack; | 1034 | target_stack_t tuc_stack; |
| 1027 | struct target_sigcontext tuc_mcontext; | 1035 | struct target_sigcontext tuc_mcontext; |
| 1028 | target_sigset_t tuc_sigmask; /* mask last for extensibility */ | 1036 | target_sigset_t tuc_sigmask; /* mask last for extensibility */ |
| 1037 | + char __unused[128 - sizeof(sigset_t)]; | ||
| 1038 | + abi_ulong tuc_regspace[128] __attribute__((__aligned__(8))); | ||
| 1029 | }; | 1039 | }; |
| 1030 | 1040 | ||
| 1031 | struct sigframe | 1041 | struct sigframe |
| @@ -1035,12 +1045,19 @@ struct sigframe | @@ -1035,12 +1045,19 @@ struct sigframe | ||
| 1035 | abi_ulong retcode; | 1045 | abi_ulong retcode; |
| 1036 | }; | 1046 | }; |
| 1037 | 1047 | ||
| 1038 | -struct rt_sigframe | 1048 | +struct rt_sigframe_v1 |
| 1039 | { | 1049 | { |
| 1040 | abi_ulong pinfo; | 1050 | abi_ulong pinfo; |
| 1041 | abi_ulong puc; | 1051 | abi_ulong puc; |
| 1042 | struct target_siginfo info; | 1052 | struct target_siginfo info; |
| 1043 | - struct target_ucontext uc; | 1053 | + struct target_ucontext_v1 uc; |
| 1054 | + abi_ulong retcode; | ||
| 1055 | +}; | ||
| 1056 | + | ||
| 1057 | +struct rt_sigframe_v2 | ||
| 1058 | +{ | ||
| 1059 | + struct target_siginfo info; | ||
| 1060 | + struct target_ucontext_v2 uc; | ||
| 1044 | abi_ulong retcode; | 1061 | abi_ulong retcode; |
| 1045 | }; | 1062 | }; |
| 1046 | 1063 | ||
| @@ -1191,11 +1208,11 @@ end: | @@ -1191,11 +1208,11 @@ end: | ||
| 1191 | } | 1208 | } |
| 1192 | 1209 | ||
| 1193 | /* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */ | 1210 | /* compare linux/arch/arm/kernel/signal.c:setup_rt_frame() */ |
| 1194 | -static void setup_rt_frame(int usig, struct emulated_sigaction *ka, | ||
| 1195 | - target_siginfo_t *info, | ||
| 1196 | - target_sigset_t *set, CPUState *env) | 1211 | +static void setup_rt_frame_v1(int usig, struct emulated_sigaction *ka, |
| 1212 | + target_siginfo_t *info, | ||
| 1213 | + target_sigset_t *set, CPUState *env) | ||
| 1197 | { | 1214 | { |
| 1198 | - struct rt_sigframe *frame; | 1215 | + struct rt_sigframe_v1 *frame; |
| 1199 | abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); | 1216 | abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); |
| 1200 | struct target_sigaltstack stack; | 1217 | struct target_sigaltstack stack; |
| 1201 | int i, err = 0; | 1218 | int i, err = 0; |
| @@ -1204,14 +1221,14 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, | @@ -1204,14 +1221,14 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, | ||
| 1204 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) | 1221 | if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) |
| 1205 | return /* 1 */; | 1222 | return /* 1 */; |
| 1206 | 1223 | ||
| 1207 | - info_addr = frame_addr + offsetof(struct rt_sigframe, info); | 1224 | + info_addr = frame_addr + offsetof(struct rt_sigframe_v1, info); |
| 1208 | __put_user_error(info_addr, &frame->pinfo, err); | 1225 | __put_user_error(info_addr, &frame->pinfo, err); |
| 1209 | - uc_addr = frame_addr + offsetof(struct rt_sigframe, uc); | 1226 | + uc_addr = frame_addr + offsetof(struct rt_sigframe_v1, uc); |
| 1210 | __put_user_error(uc_addr, &frame->puc, err); | 1227 | __put_user_error(uc_addr, &frame->puc, err); |
| 1211 | err |= copy_siginfo_to_user(&frame->info, info); | 1228 | err |= copy_siginfo_to_user(&frame->info, info); |
| 1212 | 1229 | ||
| 1213 | /* Clear all the bits of the ucontext we don't use. */ | 1230 | /* Clear all the bits of the ucontext we don't use. */ |
| 1214 | - memset(&frame->uc, 0, offsetof(struct target_ucontext, tuc_mcontext)); | 1231 | + memset(&frame->uc, 0, offsetof(struct target_ucontext_v1, tuc_mcontext)); |
| 1215 | 1232 | ||
| 1216 | memset(&stack, 0, sizeof(stack)); | 1233 | memset(&stack, 0, sizeof(stack)); |
| 1217 | __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); | 1234 | __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp); |
| @@ -1228,7 +1245,55 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, | @@ -1228,7 +1245,55 @@ static void setup_rt_frame(int usig, struct emulated_sigaction *ka, | ||
| 1228 | 1245 | ||
| 1229 | if (err == 0) | 1246 | if (err == 0) |
| 1230 | err = setup_return(env, ka, &frame->retcode, frame_addr, usig, | 1247 | err = setup_return(env, ka, &frame->retcode, frame_addr, usig, |
| 1231 | - frame_addr + offsetof(struct rt_sigframe, retcode)); | 1248 | + frame_addr + offsetof(struct rt_sigframe_v1, retcode)); |
| 1249 | + | ||
| 1250 | + if (err == 0) { | ||
| 1251 | + env->regs[1] = info_addr; | ||
| 1252 | + env->regs[2] = uc_addr; | ||
| 1253 | + } | ||
| 1254 | + | ||
| 1255 | +end: | ||
| 1256 | + unlock_user_struct(frame, frame_addr, 1); | ||
| 1257 | + | ||
| 1258 | + // return err; | ||
| 1259 | +} | ||
| 1260 | + | ||
| 1261 | +static void setup_rt_frame_v2(int usig, struct emulated_sigaction *ka, | ||
| 1262 | + target_siginfo_t *info, | ||
| 1263 | + target_sigset_t *set, CPUState *env) | ||
| 1264 | +{ | ||
| 1265 | + struct rt_sigframe_v2 *frame; | ||
| 1266 | + abi_ulong frame_addr = get_sigframe(ka, env, sizeof(*frame)); | ||
| 1267 | + struct target_sigaltstack stack; | ||
| 1268 | + int i, err = 0; | ||
| 1269 | + abi_ulong info_addr, uc_addr; | ||
| 1270 | + | ||
| 1271 | + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) | ||
| 1272 | + return /* 1 */; | ||
| 1273 | + | ||
| 1274 | + info_addr = frame_addr + offsetof(struct rt_sigframe_v2, info); | ||
| 1275 | + uc_addr = frame_addr + offsetof(struct rt_sigframe_v2, uc); | ||
| 1276 | + err |= copy_siginfo_to_user(&frame->info, info); | ||
| 1277 | + | ||
| 1278 | + /* Clear all the bits of the ucontext we don't use. */ | ||
| 1279 | + memset(&frame->uc, 0, offsetof(struct target_ucontext_v2, tuc_mcontext)); | ||
| 1280 | + | ||
| 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)); | ||
| 1286 | + | ||
| 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 | + } | ||
| 1293 | + | ||
| 1294 | + if (err == 0) | ||
| 1295 | + err = setup_return(env, ka, &frame->retcode, frame_addr, usig, | ||
| 1296 | + frame_addr + offsetof(struct rt_sigframe_v2, retcode)); | ||
| 1232 | 1297 | ||
| 1233 | if (err == 0) { | 1298 | if (err == 0) { |
| 1234 | /* | 1299 | /* |
| @@ -1246,6 +1311,17 @@ end: | @@ -1246,6 +1311,17 @@ end: | ||
| 1246 | // return err; | 1311 | // return err; |
| 1247 | } | 1312 | } |
| 1248 | 1313 | ||
| 1314 | +static void setup_rt_frame(int usig, struct emulated_sigaction *ka, | ||
| 1315 | + target_siginfo_t *info, | ||
| 1316 | + target_sigset_t *set, CPUState *env) | ||
| 1317 | +{ | ||
| 1318 | + if (get_osversion() >= 0x020612) { | ||
| 1319 | + setup_rt_frame_v2(usig, ka, info, set, env); | ||
| 1320 | + } else { | ||
| 1321 | + setup_rt_frame_v1(usig, ka, info, set, env); | ||
| 1322 | + } | ||
| 1323 | +} | ||
| 1324 | + | ||
| 1249 | static int | 1325 | static int |
| 1250 | restore_sigcontext(CPUState *env, struct target_sigcontext *sc) | 1326 | restore_sigcontext(CPUState *env, struct target_sigcontext *sc) |
| 1251 | { | 1327 | { |
| @@ -1325,10 +1401,51 @@ badframe: | @@ -1325,10 +1401,51 @@ badframe: | ||
| 1325 | return 0; | 1401 | return 0; |
| 1326 | } | 1402 | } |
| 1327 | 1403 | ||
| 1328 | -long do_rt_sigreturn(CPUState *env) | 1404 | +long do_rt_sigreturn_v1(CPUState *env) |
| 1329 | { | 1405 | { |
| 1330 | abi_ulong frame_addr; | 1406 | abi_ulong frame_addr; |
| 1331 | - struct rt_sigframe *frame; | 1407 | + struct rt_sigframe_v1 *frame; |
| 1408 | + sigset_t host_set; | ||
| 1409 | + | ||
| 1410 | + /* | ||
| 1411 | + * Since we stacked the signal on a 64-bit boundary, | ||
| 1412 | + * then 'sp' should be word aligned here. If it's | ||
| 1413 | + * not, then the user is trying to mess with us. | ||
| 1414 | + */ | ||
| 1415 | + if (env->regs[13] & 7) | ||
| 1416 | + goto badframe; | ||
| 1417 | + | ||
| 1418 | + frame_addr = env->regs[13]; | ||
| 1419 | + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) | ||
| 1420 | + goto badframe; | ||
| 1421 | + | ||
| 1422 | + target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask); | ||
| 1423 | + sigprocmask(SIG_SETMASK, &host_set, NULL); | ||
| 1424 | + | ||
| 1425 | + if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) | ||
| 1426 | + goto badframe; | ||
| 1427 | + | ||
| 1428 | + if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v1, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) | ||
| 1429 | + goto badframe; | ||
| 1430 | + | ||
| 1431 | +#if 0 | ||
| 1432 | + /* Send SIGTRAP if we're single-stepping */ | ||
| 1433 | + if (ptrace_cancel_bpt(current)) | ||
| 1434 | + send_sig(SIGTRAP, current, 1); | ||
| 1435 | +#endif | ||
| 1436 | + unlock_user_struct(frame, frame_addr, 0); | ||
| 1437 | + return env->regs[0]; | ||
| 1438 | + | ||
| 1439 | +badframe: | ||
| 1440 | + unlock_user_struct(frame, frame_addr, 0); | ||
| 1441 | + force_sig(SIGSEGV /* , current */); | ||
| 1442 | + return 0; | ||
| 1443 | +} | ||
| 1444 | + | ||
| 1445 | +long do_rt_sigreturn_v2(CPUState *env) | ||
| 1446 | +{ | ||
| 1447 | + abi_ulong frame_addr; | ||
| 1448 | + struct rt_sigframe_v2 *frame; | ||
| 1332 | sigset_t host_set; | 1449 | sigset_t host_set; |
| 1333 | 1450 | ||
| 1334 | /* | 1451 | /* |
| @@ -1349,7 +1466,7 @@ long do_rt_sigreturn(CPUState *env) | @@ -1349,7 +1466,7 @@ long do_rt_sigreturn(CPUState *env) | ||
| 1349 | if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) | 1466 | if (restore_sigcontext(env, &frame->uc.tuc_mcontext)) |
| 1350 | goto badframe; | 1467 | goto badframe; |
| 1351 | 1468 | ||
| 1352 | - if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) | 1469 | + if (do_sigaltstack(frame_addr + offsetof(struct rt_sigframe_v2, uc.tuc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) |
| 1353 | goto badframe; | 1470 | goto badframe; |
| 1354 | 1471 | ||
| 1355 | #if 0 | 1472 | #if 0 |
| @@ -1366,6 +1483,15 @@ badframe: | @@ -1366,6 +1483,15 @@ badframe: | ||
| 1366 | return 0; | 1483 | return 0; |
| 1367 | } | 1484 | } |
| 1368 | 1485 | ||
| 1486 | +long do_rt_sigreturn(CPUState *env) | ||
| 1487 | +{ | ||
| 1488 | + if (get_osversion() >= 0x020612) { | ||
| 1489 | + return do_rt_sigreturn_v2(env); | ||
| 1490 | + } else { | ||
| 1491 | + return do_rt_sigreturn_v1(env); | ||
| 1492 | + } | ||
| 1493 | +} | ||
| 1494 | + | ||
| 1369 | #elif defined(TARGET_SPARC) | 1495 | #elif defined(TARGET_SPARC) |
| 1370 | 1496 | ||
| 1371 | #define __SUNOS_MAXWIN 31 | 1497 | #define __SUNOS_MAXWIN 31 |
linux-user/syscall.c
| @@ -3054,6 +3054,37 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr, | @@ -3054,6 +3054,37 @@ static inline abi_long host_to_target_timespec(abi_ulong target_addr, | ||
| 3054 | unlock_user_struct(target_ts, target_addr, 1); | 3054 | unlock_user_struct(target_ts, target_addr, 1); |
| 3055 | } | 3055 | } |
| 3056 | 3056 | ||
| 3057 | +int get_osversion(void) | ||
| 3058 | +{ | ||
| 3059 | + static int osversion; | ||
| 3060 | + struct new_utsname buf; | ||
| 3061 | + const char *s; | ||
| 3062 | + int i, n, tmp; | ||
| 3063 | + if (osversion) | ||
| 3064 | + return osversion; | ||
| 3065 | + if (qemu_uname_release && *qemu_uname_release) { | ||
| 3066 | + s = qemu_uname_release; | ||
| 3067 | + } else { | ||
| 3068 | + if (sys_uname(&buf)) | ||
| 3069 | + return 0; | ||
| 3070 | + s = buf.release; | ||
| 3071 | + } | ||
| 3072 | + tmp = 0; | ||
| 3073 | + for (i = 0; i < 3; i++) { | ||
| 3074 | + n = 0; | ||
| 3075 | + while (*s >= '0' && *s <= '9') { | ||
| 3076 | + n *= 10; | ||
| 3077 | + n += *s - '0'; | ||
| 3078 | + s++; | ||
| 3079 | + } | ||
| 3080 | + tmp = (tmp << 8) + n; | ||
| 3081 | + if (*s == '.') | ||
| 3082 | + s++; | ||
| 3083 | + } | ||
| 3084 | + osversion = tmp; | ||
| 3085 | + return osversion; | ||
| 3086 | +} | ||
| 3087 | + | ||
| 3057 | /* do_syscall() should always have a single exit point at the end so | 3088 | /* do_syscall() should always have a single exit point at the end so |
| 3058 | that actions, such as logging of syscall results, can be performed. | 3089 | that actions, such as logging of syscall results, can be performed. |
| 3059 | All errnos that do_syscall() returns must be -TARGET_<errcode>. */ | 3090 | All errnos that do_syscall() returns must be -TARGET_<errcode>. */ |