| 1 | /* |
| 2 | * BSD syscalls |
| 3 | * |
| 4 | * Copyright (c) 2003-2008 Fabrice Bellard |
| 5 | * Copyright (c) 2013-2014 Stacey D. Son |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; either version 2 of the License, or |
| 10 | * (at your option) any later version. |
| 11 | * |
| 12 | * This program is distributed in the hope that it will be useful, |
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | * GNU General Public License for more details. |
| 16 | * |
| 17 | * You should have received a copy of the GNU General Public License |
| 18 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 19 | */ |
| 20 | #include "qemu/osdep.h" |
| 21 | #include "qemu/cutils.h" |
| 22 | #include "qemu/path.h" |
| 23 | #include <sys/syscall.h> |
| 24 | #include <sys/cdefs.h> |
| 25 | #include <sys/param.h> |
| 26 | #include <sys/mount.h> |
| 27 | #include <sys/sysctl.h> |
| 28 | #include <utime.h> |
| 29 | |
| 30 | #include "include/gdbstub/syscalls.h" |
| 31 | |
| 32 | #include "qemu.h" |
| 33 | #include "signal-common.h" |
| 34 | |
| 35 | /* BSD independent syscall shims */ |
| 36 | #include "bsd-file.h" |
| 37 | #include "bsd-ioctl.h" |
| 38 | #include "bsd-mem.h" |
| 39 | #include "bsd-proc.h" |
| 40 | #include "bsd-misc.h" |
| 41 | |
| 42 | /* BSD dependent syscall shims */ |
| 43 | #include "os-stat.h" |
| 44 | #include "os-proc.h" |
| 45 | #include "os-misc.h" |
| 46 | |
| 47 | /* I/O */ |
| 48 | safe_syscall3(int, open, const char *, path, int, flags, mode_t, mode); |
| 49 | safe_syscall4(int, openat, int, fd, const char *, path, int, flags, mode_t, |
| 50 | mode); |
| 51 | |
| 52 | safe_syscall3(ssize_t, read, int, fd, void *, buf, size_t, nbytes); |
| 53 | safe_syscall4(ssize_t, pread, int, fd, void *, buf, size_t, nbytes, off_t, |
| 54 | offset); |
| 55 | safe_syscall3(ssize_t, readv, int, fd, const struct iovec *, iov, int, iovcnt); |
| 56 | safe_syscall4(ssize_t, preadv, int, fd, const struct iovec *, iov, int, iovcnt, |
| 57 | off_t, offset); |
| 58 | |
| 59 | safe_syscall3(ssize_t, write, int, fd, void *, buf, size_t, nbytes); |
| 60 | safe_syscall4(ssize_t, pwrite, int, fd, void *, buf, size_t, nbytes, off_t, |
| 61 | offset); |
| 62 | safe_syscall3(ssize_t, writev, int, fd, const struct iovec *, iov, int, iovcnt); |
| 63 | safe_syscall4(ssize_t, pwritev, int, fd, const struct iovec *, iov, int, iovcnt, |
| 64 | off_t, offset); |
| 65 | |
| 66 | /* used in os-proc */ |
| 67 | safe_syscall4(pid_t, wait4, pid_t, wpid, int *, status, int, options, |
| 68 | struct rusage *, rusage); |
| 69 | safe_syscall6(pid_t, wait6, idtype_t, idtype, id_t, id, int *, status, int, |
| 70 | options, struct __wrusage *, wrusage, siginfo_t *, infop); |
| 71 | |
| 72 | /* |
| 73 | * errno conversion. |
| 74 | */ |
| 75 | abi_long get_errno(abi_long ret) |
| 76 | { |
| 77 | if (ret == -1) { |
| 78 | return -host_to_target_errno(errno); |
| 79 | } else { |
| 80 | return ret; |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | int host_to_target_errno(int err) |
| 85 | { |
| 86 | /* |
| 87 | * All the BSDs have the property that the error numbers are uniform across |
| 88 | * all architectures for a given BSD, though they may vary between different |
| 89 | * BSDs. |
| 90 | */ |
| 91 | return err; |
| 92 | } |
| 93 | |
| 94 | bool is_error(abi_long ret) |
| 95 | { |
| 96 | return (abi_ulong)ret >= (abi_ulong)(-4096); |
| 97 | } |
| 98 | |
| 99 | /* |
| 100 | * Unlocks a iovec. Unlike unlock_iovec, it assumes the tvec array itself is |
| 101 | * already locked from target_addr. It will be unlocked as well as all the iovec |
| 102 | * elements. |
| 103 | */ |
| 104 | static void helper_unlock_iovec(struct target_iovec *target_vec, |
| 105 | abi_ulong target_addr, struct iovec *vec, |
| 106 | int count, int copy) |
| 107 | { |
| 108 | for (int i = 0; i < count; i++) { |
| 109 | abi_ulong base = tswapal(target_vec[i].iov_base); |
| 110 | |
| 111 | if (vec[i].iov_base) { |
| 112 | unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); |
| 113 | } |
| 114 | } |
| 115 | unlock_user(target_vec, target_addr, 0); |
| 116 | } |
| 117 | |
| 118 | struct iovec *lock_iovec(int type, abi_ulong target_addr, |
| 119 | int count, int copy) |
| 120 | { |
| 121 | struct target_iovec *target_vec; |
| 122 | struct iovec *vec; |
| 123 | abi_ulong total_len, max_len; |
| 124 | int i; |
| 125 | int err = 0; |
| 126 | |
| 127 | if (count == 0) { |
| 128 | errno = 0; |
| 129 | return NULL; |
| 130 | } |
| 131 | if (count < 0 || count > IOV_MAX) { |
| 132 | errno = EINVAL; |
| 133 | return NULL; |
| 134 | } |
| 135 | |
| 136 | vec = g_try_new0(struct iovec, count); |
| 137 | if (vec == NULL) { |
| 138 | errno = ENOMEM; |
| 139 | return NULL; |
| 140 | } |
| 141 | |
| 142 | target_vec = lock_user(VERIFY_READ, target_addr, |
| 143 | count * sizeof(struct target_iovec), 1); |
| 144 | if (target_vec == NULL) { |
| 145 | err = EFAULT; |
| 146 | goto fail2; |
| 147 | } |
| 148 | |
| 149 | max_len = 0x7fffffff & MIN(TARGET_PAGE_MASK, PAGE_MASK); |
| 150 | total_len = 0; |
| 151 | |
| 152 | for (i = 0; i < count; i++) { |
| 153 | abi_ulong base = tswapal(target_vec[i].iov_base); |
| 154 | abi_long len = tswapal(target_vec[i].iov_len); |
| 155 | |
| 156 | if (len < 0) { |
| 157 | err = EINVAL; |
| 158 | goto fail; |
| 159 | } else if (len == 0) { |
| 160 | /* Zero length pointer is ignored. */ |
| 161 | vec[i].iov_base = 0; |
| 162 | } else { |
| 163 | vec[i].iov_base = lock_user(type, base, len, copy); |
| 164 | /* |
| 165 | * If the first buffer pointer is bad, this is a fault. But |
| 166 | * subsequent bad buffers will result in a partial write; this is |
| 167 | * realized by filling the vector with null pointers and zero |
| 168 | * lengths. |
| 169 | */ |
| 170 | if (!vec[i].iov_base) { |
| 171 | if (i == 0) { |
| 172 | err = EFAULT; |
| 173 | goto fail; |
| 174 | } else { |
| 175 | /* |
| 176 | * Fail all the subsequent addresses, they are already |
| 177 | * zero'd. |
| 178 | */ |
| 179 | goto out; |
| 180 | } |
| 181 | } |
| 182 | if (len > max_len - total_len) { |
| 183 | len = max_len - total_len; |
| 184 | } |
| 185 | } |
| 186 | vec[i].iov_len = len; |
| 187 | total_len += len; |
| 188 | } |
| 189 | out: |
| 190 | unlock_user(target_vec, target_addr, 0); |
| 191 | return vec; |
| 192 | |
| 193 | fail: |
| 194 | helper_unlock_iovec(target_vec, target_addr, vec, i, copy); |
| 195 | fail2: |
| 196 | g_free(vec); |
| 197 | errno = err; |
| 198 | return NULL; |
| 199 | } |
| 200 | |
| 201 | void unlock_iovec(struct iovec *vec, abi_ulong target_addr, |
| 202 | int count, int copy) |
| 203 | { |
| 204 | struct target_iovec *target_vec; |
| 205 | |
| 206 | target_vec = lock_user(VERIFY_READ, target_addr, |
| 207 | count * sizeof(struct target_iovec), 1); |
| 208 | if (target_vec) { |
| 209 | helper_unlock_iovec(target_vec, target_addr, vec, count, copy); |
| 210 | } |
| 211 | |
| 212 | g_free(vec); |
| 213 | } |
| 214 | |
| 215 | /* |
| 216 | * All errnos that freebsd_syscall() returns must be -TARGET_<errcode>. |
| 217 | */ |
| 218 | static abi_long freebsd_syscall(void *cpu_env, int num, abi_long arg1, |
| 219 | abi_long arg2, abi_long arg3, abi_long arg4, |
| 220 | abi_long arg5, abi_long arg6, abi_long arg7, |
| 221 | abi_long arg8) |
| 222 | { |
| 223 | abi_long ret; |
| 224 | |
| 225 | switch (num) { |
| 226 | /* |
| 227 | * process system calls |
| 228 | */ |
| 229 | case TARGET_FREEBSD_NR_fork: /* fork(2) */ |
| 230 | ret = do_freebsd_fork(cpu_env); |
| 231 | break; |
| 232 | |
| 233 | case TARGET_FREEBSD_NR_vfork: /* vfork(2) */ |
| 234 | ret = do_freebsd_vfork(cpu_env); |
| 235 | break; |
| 236 | |
| 237 | case TARGET_FREEBSD_NR_rfork: /* rfork(2) */ |
| 238 | ret = do_freebsd_rfork(cpu_env, arg1); |
| 239 | break; |
| 240 | |
| 241 | case TARGET_FREEBSD_NR_pdfork: /* pdfork(2) */ |
| 242 | ret = do_freebsd_pdfork(cpu_env, arg1, arg2); |
| 243 | break; |
| 244 | |
| 245 | case TARGET_FREEBSD_NR_execve: /* execve(2) */ |
| 246 | ret = do_freebsd_execve(arg1, arg2, arg3); |
| 247 | break; |
| 248 | |
| 249 | case TARGET_FREEBSD_NR_fexecve: /* fexecve(2) */ |
| 250 | ret = do_freebsd_fexecve(arg1, arg2, arg3); |
| 251 | break; |
| 252 | |
| 253 | case TARGET_FREEBSD_NR_wait4: /* wait4(2) */ |
| 254 | ret = do_freebsd_wait4(arg1, arg2, arg3, arg4); |
| 255 | break; |
| 256 | |
| 257 | case TARGET_FREEBSD_NR_wait6: /* wait6(2) */ |
| 258 | ret = do_freebsd_wait6(cpu_env, arg1, arg2, arg3, |
| 259 | arg4, arg5, arg6, arg7, arg8); |
| 260 | break; |
| 261 | |
| 262 | case TARGET_FREEBSD_NR_exit: /* exit(2) */ |
| 263 | ret = do_bsd_exit(cpu_env, arg1); |
| 264 | break; |
| 265 | |
| 266 | case TARGET_FREEBSD_NR_getgroups: /* getgroups(2) */ |
| 267 | ret = do_bsd_getgroups(arg1, arg2); |
| 268 | break; |
| 269 | |
| 270 | case TARGET_FREEBSD_NR_setgroups: /* setgroups(2) */ |
| 271 | ret = do_bsd_setgroups(arg1, arg2); |
| 272 | break; |
| 273 | |
| 274 | case TARGET_FREEBSD_NR_umask: /* umask(2) */ |
| 275 | ret = do_bsd_umask(arg1); |
| 276 | break; |
| 277 | |
| 278 | case TARGET_FREEBSD_NR_setlogin: /* setlogin(2) */ |
| 279 | ret = do_bsd_setlogin(arg1); |
| 280 | break; |
| 281 | |
| 282 | case TARGET_FREEBSD_NR_getlogin: /* getlogin(2) */ |
| 283 | ret = do_bsd_getlogin(arg1, arg2); |
| 284 | break; |
| 285 | |
| 286 | case TARGET_FREEBSD_NR_getrusage: /* getrusage(2) */ |
| 287 | ret = do_bsd_getrusage(arg1, arg2); |
| 288 | break; |
| 289 | |
| 290 | case TARGET_FREEBSD_NR_getrlimit: /* getrlimit(2) */ |
| 291 | ret = do_bsd_getrlimit(arg1, arg2); |
| 292 | break; |
| 293 | |
| 294 | case TARGET_FREEBSD_NR_setrlimit: /* setrlimit(2) */ |
| 295 | ret = do_bsd_setrlimit(arg1, arg2); |
| 296 | break; |
| 297 | |
| 298 | case TARGET_FREEBSD_NR_getpid: /* getpid(2) */ |
| 299 | ret = do_bsd_getpid(); |
| 300 | break; |
| 301 | |
| 302 | case TARGET_FREEBSD_NR_getppid: /* getppid(2) */ |
| 303 | ret = do_bsd_getppid(); |
| 304 | break; |
| 305 | |
| 306 | case TARGET_FREEBSD_NR_getuid: /* getuid(2) */ |
| 307 | ret = do_bsd_getuid(); |
| 308 | break; |
| 309 | |
| 310 | case TARGET_FREEBSD_NR_geteuid: /* geteuid(2) */ |
| 311 | ret = do_bsd_geteuid(); |
| 312 | break; |
| 313 | |
| 314 | case TARGET_FREEBSD_NR_getgid: /* getgid(2) */ |
| 315 | ret = do_bsd_getgid(); |
| 316 | break; |
| 317 | |
| 318 | case TARGET_FREEBSD_NR_getegid: /* getegid(2) */ |
| 319 | ret = do_bsd_getegid(); |
| 320 | break; |
| 321 | |
| 322 | case TARGET_FREEBSD_NR_setuid: /* setuid(2) */ |
| 323 | ret = do_bsd_setuid(arg1); |
| 324 | break; |
| 325 | |
| 326 | case TARGET_FREEBSD_NR_seteuid: /* seteuid(2) */ |
| 327 | ret = do_bsd_seteuid(arg1); |
| 328 | break; |
| 329 | |
| 330 | case TARGET_FREEBSD_NR_setgid: /* setgid(2) */ |
| 331 | ret = do_bsd_setgid(arg1); |
| 332 | break; |
| 333 | |
| 334 | case TARGET_FREEBSD_NR_setegid: /* setegid(2) */ |
| 335 | ret = do_bsd_setegid(arg1); |
| 336 | break; |
| 337 | |
| 338 | case TARGET_FREEBSD_NR_getpgrp: /* getpgrp(2) */ |
| 339 | ret = do_bsd_getpgrp(); |
| 340 | break; |
| 341 | |
| 342 | case TARGET_FREEBSD_NR_getpgid: /* getpgid(2) */ |
| 343 | ret = do_bsd_getpgid(arg1); |
| 344 | break; |
| 345 | |
| 346 | case TARGET_FREEBSD_NR_setpgid: /* setpgid(2) */ |
| 347 | ret = do_bsd_setpgid(arg1, arg2); |
| 348 | break; |
| 349 | |
| 350 | case TARGET_FREEBSD_NR_setreuid: /* setreuid(2) */ |
| 351 | ret = do_bsd_setreuid(arg1, arg2); |
| 352 | break; |
| 353 | |
| 354 | case TARGET_FREEBSD_NR_setregid: /* setregid(2) */ |
| 355 | ret = do_bsd_setregid(arg1, arg2); |
| 356 | break; |
| 357 | |
| 358 | case TARGET_FREEBSD_NR_getresuid: /* getresuid(2) */ |
| 359 | ret = do_bsd_getresuid(arg1, arg2, arg3); |
| 360 | break; |
| 361 | |
| 362 | case TARGET_FREEBSD_NR_getresgid: /* getresgid(2) */ |
| 363 | ret = do_bsd_getresgid(arg1, arg2, arg3); |
| 364 | break; |
| 365 | |
| 366 | case TARGET_FREEBSD_NR_setresuid: /* setresuid(2) */ |
| 367 | ret = do_bsd_setresuid(arg1, arg2, arg3); |
| 368 | break; |
| 369 | |
| 370 | case TARGET_FREEBSD_NR_setresgid: /* setresgid(2) */ |
| 371 | ret = do_bsd_setresgid(arg1, arg2, arg3); |
| 372 | break; |
| 373 | |
| 374 | case TARGET_FREEBSD_NR_getsid: /* getsid(2) */ |
| 375 | ret = do_bsd_getsid(arg1); |
| 376 | break; |
| 377 | |
| 378 | case TARGET_FREEBSD_NR_setsid: /* setsid(2) */ |
| 379 | ret = do_bsd_setsid(); |
| 380 | break; |
| 381 | |
| 382 | case TARGET_FREEBSD_NR_issetugid: /* issetugid(2) */ |
| 383 | ret = do_bsd_issetugid(); |
| 384 | break; |
| 385 | |
| 386 | case TARGET_FREEBSD_NR_profil: /* profil(2) */ |
| 387 | ret = do_bsd_profil(arg1, arg2, arg3, arg4); |
| 388 | break; |
| 389 | |
| 390 | case TARGET_FREEBSD_NR_ktrace: /* ktrace(2) */ |
| 391 | ret = do_bsd_ktrace(arg1, arg2, arg3, arg4); |
| 392 | break; |
| 393 | |
| 394 | case TARGET_FREEBSD_NR_setloginclass: /* setloginclass(2) */ |
| 395 | ret = do_freebsd_setloginclass(arg1); |
| 396 | break; |
| 397 | |
| 398 | case TARGET_FREEBSD_NR_getloginclass: /* getloginclass(2) */ |
| 399 | ret = do_freebsd_getloginclass(arg1, arg2); |
| 400 | break; |
| 401 | |
| 402 | case TARGET_FREEBSD_NR_pdgetpid: /* pdgetpid(2) */ |
| 403 | ret = do_freebsd_pdgetpid(arg1, arg2); |
| 404 | break; |
| 405 | |
| 406 | case TARGET_FREEBSD_NR___setugid: /* undocumented */ |
| 407 | ret = do_freebsd___setugid(arg1); |
| 408 | break; |
| 409 | |
| 410 | case TARGET_FREEBSD_NR_utrace: /* utrace(2) */ |
| 411 | ret = do_bsd_utrace(arg1, arg2); |
| 412 | break; |
| 413 | |
| 414 | case TARGET_FREEBSD_NR_ptrace: /* ptrace(2) */ |
| 415 | ret = do_bsd_ptrace(arg1, arg2, arg3, arg4); |
| 416 | break; |
| 417 | |
| 418 | case TARGET_FREEBSD_NR_getpriority: /* getpriority(2) */ |
| 419 | ret = do_bsd_getpriority(arg1, arg2); |
| 420 | break; |
| 421 | |
| 422 | case TARGET_FREEBSD_NR_setpriority: /* setpriority(2) */ |
| 423 | ret = do_bsd_setpriority(arg1, arg2, arg3); |
| 424 | break; |
| 425 | |
| 426 | case TARGET_FREEBSD_NR_procctl: /* procctl(2) */ |
| 427 | ret = do_freebsd_procctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); |
| 428 | break; |
| 429 | |
| 430 | /* |
| 431 | * File system calls. |
| 432 | */ |
| 433 | case TARGET_FREEBSD_NR_read: /* read(2) */ |
| 434 | ret = do_bsd_read(arg1, arg2, arg3); |
| 435 | break; |
| 436 | |
| 437 | case TARGET_FREEBSD_NR_pread: /* pread(2) */ |
| 438 | ret = do_bsd_pread(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); |
| 439 | break; |
| 440 | |
| 441 | case TARGET_FREEBSD_NR_readv: /* readv(2) */ |
| 442 | ret = do_bsd_readv(arg1, arg2, arg3); |
| 443 | break; |
| 444 | |
| 445 | case TARGET_FREEBSD_NR_preadv: /* preadv(2) */ |
| 446 | ret = do_bsd_preadv(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); |
| 447 | break; |
| 448 | |
| 449 | case TARGET_FREEBSD_NR_write: /* write(2) */ |
| 450 | ret = do_bsd_write(arg1, arg2, arg3); |
| 451 | break; |
| 452 | |
| 453 | case TARGET_FREEBSD_NR_pwrite: /* pwrite(2) */ |
| 454 | ret = do_bsd_pwrite(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); |
| 455 | break; |
| 456 | |
| 457 | case TARGET_FREEBSD_NR_writev: /* writev(2) */ |
| 458 | ret = do_bsd_writev(arg1, arg2, arg3); |
| 459 | break; |
| 460 | |
| 461 | case TARGET_FREEBSD_NR_pwritev: /* pwritev(2) */ |
| 462 | ret = do_bsd_pwritev(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); |
| 463 | break; |
| 464 | |
| 465 | case TARGET_FREEBSD_NR_open: /* open(2) */ |
| 466 | ret = do_bsd_open(arg1, arg2, arg3); |
| 467 | break; |
| 468 | |
| 469 | case TARGET_FREEBSD_NR_openat: /* openat(2) */ |
| 470 | ret = do_bsd_openat(arg1, arg2, arg3, arg4); |
| 471 | break; |
| 472 | |
| 473 | case TARGET_FREEBSD_NR_close: /* close(2) */ |
| 474 | ret = do_bsd_close(arg1); |
| 475 | break; |
| 476 | |
| 477 | case TARGET_FREEBSD_NR_fdatasync: /* fdatasync(2) */ |
| 478 | ret = do_bsd_fdatasync(arg1); |
| 479 | break; |
| 480 | |
| 481 | case TARGET_FREEBSD_NR_fsync: /* fsync(2) */ |
| 482 | ret = do_bsd_fsync(arg1); |
| 483 | break; |
| 484 | |
| 485 | case TARGET_FREEBSD_NR_freebsd12_closefrom: /* closefrom(2) */ |
| 486 | ret = do_bsd_closefrom(arg1); |
| 487 | break; |
| 488 | |
| 489 | case TARGET_FREEBSD_NR_revoke: /* revoke(2) */ |
| 490 | ret = do_bsd_revoke(arg1); |
| 491 | break; |
| 492 | |
| 493 | case TARGET_FREEBSD_NR_access: /* access(2) */ |
| 494 | ret = do_bsd_access(arg1, arg2); |
| 495 | break; |
| 496 | |
| 497 | case TARGET_FREEBSD_NR_eaccess: /* eaccess(2) */ |
| 498 | ret = do_bsd_eaccess(arg1, arg2); |
| 499 | break; |
| 500 | |
| 501 | case TARGET_FREEBSD_NR_faccessat: /* faccessat(2) */ |
| 502 | ret = do_bsd_faccessat(arg1, arg2, arg3, arg4); |
| 503 | break; |
| 504 | |
| 505 | case TARGET_FREEBSD_NR_chdir: /* chdir(2) */ |
| 506 | ret = do_bsd_chdir(arg1); |
| 507 | break; |
| 508 | |
| 509 | case TARGET_FREEBSD_NR_fchdir: /* fchdir(2) */ |
| 510 | ret = do_bsd_fchdir(arg1); |
| 511 | break; |
| 512 | |
| 513 | case TARGET_FREEBSD_NR_rename: /* rename(2) */ |
| 514 | ret = do_bsd_rename(arg1, arg2); |
| 515 | break; |
| 516 | |
| 517 | case TARGET_FREEBSD_NR_renameat: /* renameat(2) */ |
| 518 | ret = do_bsd_renameat(arg1, arg2, arg3, arg4); |
| 519 | break; |
| 520 | |
| 521 | case TARGET_FREEBSD_NR_link: /* link(2) */ |
| 522 | ret = do_bsd_link(arg1, arg2); |
| 523 | break; |
| 524 | |
| 525 | case TARGET_FREEBSD_NR_linkat: /* linkat(2) */ |
| 526 | ret = do_bsd_linkat(arg1, arg2, arg3, arg4, arg5); |
| 527 | break; |
| 528 | |
| 529 | case TARGET_FREEBSD_NR_unlink: /* unlink(2) */ |
| 530 | ret = do_bsd_unlink(arg1); |
| 531 | break; |
| 532 | |
| 533 | case TARGET_FREEBSD_NR_unlinkat: /* unlinkat(2) */ |
| 534 | ret = do_bsd_unlinkat(arg1, arg2, arg3); |
| 535 | break; |
| 536 | |
| 537 | case TARGET_FREEBSD_NR_mkdir: /* mkdir(2) */ |
| 538 | ret = do_bsd_mkdir(arg1, arg2); |
| 539 | break; |
| 540 | |
| 541 | case TARGET_FREEBSD_NR_mkdirat: /* mkdirat(2) */ |
| 542 | ret = do_bsd_mkdirat(arg1, arg2, arg3); |
| 543 | break; |
| 544 | |
| 545 | case TARGET_FREEBSD_NR_rmdir: /* rmdir(2) (XXX no rmdirat()?) */ |
| 546 | ret = do_bsd_rmdir(arg1); |
| 547 | break; |
| 548 | |
| 549 | case TARGET_FREEBSD_NR___getcwd: /* undocumented __getcwd() */ |
| 550 | ret = do_bsd___getcwd(arg1, arg2); |
| 551 | break; |
| 552 | |
| 553 | case TARGET_FREEBSD_NR_dup: /* dup(2) */ |
| 554 | ret = do_bsd_dup(arg1); |
| 555 | break; |
| 556 | |
| 557 | case TARGET_FREEBSD_NR_dup2: /* dup2(2) */ |
| 558 | ret = do_bsd_dup2(arg1, arg2); |
| 559 | break; |
| 560 | |
| 561 | case TARGET_FREEBSD_NR_truncate: /* truncate(2) */ |
| 562 | ret = do_bsd_truncate(cpu_env, arg1, arg2, arg3, arg4); |
| 563 | break; |
| 564 | |
| 565 | case TARGET_FREEBSD_NR_ftruncate: /* ftruncate(2) */ |
| 566 | ret = do_bsd_ftruncate(cpu_env, arg1, arg2, arg3, arg4); |
| 567 | break; |
| 568 | |
| 569 | case TARGET_FREEBSD_NR_acct: /* acct(2) */ |
| 570 | ret = do_bsd_acct(arg1); |
| 571 | break; |
| 572 | |
| 573 | case TARGET_FREEBSD_NR_sync: /* sync(2) */ |
| 574 | ret = do_bsd_sync(); |
| 575 | break; |
| 576 | |
| 577 | case TARGET_FREEBSD_NR_mount: /* mount(2) */ |
| 578 | ret = do_bsd_mount(arg1, arg2, arg3, arg4); |
| 579 | break; |
| 580 | |
| 581 | case TARGET_FREEBSD_NR_unmount: /* unmount(2) */ |
| 582 | ret = do_bsd_unmount(arg1, arg2); |
| 583 | break; |
| 584 | |
| 585 | case TARGET_FREEBSD_NR_nmount: /* nmount(2) */ |
| 586 | ret = do_bsd_nmount(arg1, arg2, arg3); |
| 587 | break; |
| 588 | |
| 589 | case TARGET_FREEBSD_NR_symlink: /* symlink(2) */ |
| 590 | ret = do_bsd_symlink(arg1, arg2); |
| 591 | break; |
| 592 | |
| 593 | case TARGET_FREEBSD_NR_symlinkat: /* symlinkat(2) */ |
| 594 | ret = do_bsd_symlinkat(arg1, arg2, arg3); |
| 595 | break; |
| 596 | |
| 597 | case TARGET_FREEBSD_NR_readlink: /* readlink(2) */ |
| 598 | ret = do_bsd_readlink(cpu_env, arg1, arg2, arg3); |
| 599 | break; |
| 600 | |
| 601 | case TARGET_FREEBSD_NR_readlinkat: /* readlinkat(2) */ |
| 602 | ret = do_bsd_readlinkat(arg1, arg2, arg3, arg4); |
| 603 | break; |
| 604 | |
| 605 | case TARGET_FREEBSD_NR_chmod: /* chmod(2) */ |
| 606 | ret = do_bsd_chmod(arg1, arg2); |
| 607 | break; |
| 608 | |
| 609 | case TARGET_FREEBSD_NR_fchmod: /* fchmod(2) */ |
| 610 | ret = do_bsd_fchmod(arg1, arg2); |
| 611 | break; |
| 612 | |
| 613 | case TARGET_FREEBSD_NR_lchmod: /* lchmod(2) */ |
| 614 | ret = do_bsd_lchmod(arg1, arg2); |
| 615 | break; |
| 616 | |
| 617 | case TARGET_FREEBSD_NR_fchmodat: /* fchmodat(2) */ |
| 618 | ret = do_bsd_fchmodat(arg1, arg2, arg3, arg4); |
| 619 | break; |
| 620 | |
| 621 | case TARGET_FREEBSD_NR_freebsd11_mknod: /* mknod(2) */ |
| 622 | ret = do_bsd_freebsd11_mknod(arg1, arg2, arg3); |
| 623 | break; |
| 624 | |
| 625 | case TARGET_FREEBSD_NR_freebsd11_mknodat: /* mknodat(2) */ |
| 626 | ret = do_bsd_freebsd11_mknodat(arg1, arg2, arg3, arg4); |
| 627 | break; |
| 628 | |
| 629 | case TARGET_FREEBSD_NR_mknodat: /* mknodat(2) */ |
| 630 | ret = do_bsd_mknodat(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); |
| 631 | break; |
| 632 | |
| 633 | case TARGET_FREEBSD_NR_chown: /* chown(2) */ |
| 634 | ret = do_bsd_chown(arg1, arg2, arg3); |
| 635 | break; |
| 636 | |
| 637 | case TARGET_FREEBSD_NR_fchown: /* fchown(2) */ |
| 638 | ret = do_bsd_fchown(arg1, arg2, arg3); |
| 639 | break; |
| 640 | |
| 641 | case TARGET_FREEBSD_NR_lchown: /* lchown(2) */ |
| 642 | ret = do_bsd_lchown(arg1, arg2, arg3); |
| 643 | break; |
| 644 | |
| 645 | case TARGET_FREEBSD_NR_fchownat: /* fchownat(2) */ |
| 646 | ret = do_bsd_fchownat(arg1, arg2, arg3, arg4, arg5); |
| 647 | break; |
| 648 | |
| 649 | case TARGET_FREEBSD_NR_chflags: /* chflags(2) */ |
| 650 | ret = do_bsd_chflags(arg1, arg2); |
| 651 | break; |
| 652 | |
| 653 | case TARGET_FREEBSD_NR_lchflags: /* lchflags(2) */ |
| 654 | ret = do_bsd_lchflags(arg1, arg2); |
| 655 | break; |
| 656 | |
| 657 | case TARGET_FREEBSD_NR_fchflags: /* fchflags(2) */ |
| 658 | ret = do_bsd_fchflags(arg1, arg2); |
| 659 | break; |
| 660 | |
| 661 | case TARGET_FREEBSD_NR_chroot: /* chroot(2) */ |
| 662 | ret = do_bsd_chroot(arg1); |
| 663 | break; |
| 664 | |
| 665 | case TARGET_FREEBSD_NR_flock: /* flock(2) */ |
| 666 | ret = do_bsd_flock(arg1, arg2); |
| 667 | break; |
| 668 | |
| 669 | case TARGET_FREEBSD_NR_mkfifo: /* mkfifo(2) */ |
| 670 | ret = do_bsd_mkfifo(arg1, arg2); |
| 671 | break; |
| 672 | |
| 673 | case TARGET_FREEBSD_NR_mkfifoat: /* mkfifoat(2) */ |
| 674 | ret = do_bsd_mkfifoat(arg1, arg2, arg3); |
| 675 | break; |
| 676 | |
| 677 | case TARGET_FREEBSD_NR_pathconf: /* pathconf(2) */ |
| 678 | ret = do_bsd_pathconf(arg1, arg2); |
| 679 | break; |
| 680 | |
| 681 | case TARGET_FREEBSD_NR_lpathconf: /* lpathconf(2) */ |
| 682 | ret = do_bsd_lpathconf(arg1, arg2); |
| 683 | break; |
| 684 | |
| 685 | case TARGET_FREEBSD_NR_fpathconf: /* fpathconf(2) */ |
| 686 | ret = do_bsd_fpathconf(arg1, arg2); |
| 687 | break; |
| 688 | |
| 689 | case TARGET_FREEBSD_NR_undelete: /* undelete(2) */ |
| 690 | ret = do_bsd_undelete(arg1); |
| 691 | break; |
| 692 | |
| 693 | /* |
| 694 | * ioctl(2) |
| 695 | */ |
| 696 | case TARGET_FREEBSD_NR_ioctl: /* ioctl(2) */ |
| 697 | ret = do_bsd_ioctl(arg1, arg2, arg3); |
| 698 | break; |
| 699 | |
| 700 | /* |
| 701 | * stat system calls |
| 702 | */ |
| 703 | case TARGET_FREEBSD_NR_freebsd11_stat: /* stat(2) */ |
| 704 | ret = do_freebsd11_stat(arg1, arg2); |
| 705 | break; |
| 706 | |
| 707 | case TARGET_FREEBSD_NR_freebsd11_lstat: /* lstat(2) */ |
| 708 | ret = do_freebsd11_lstat(arg1, arg2); |
| 709 | break; |
| 710 | |
| 711 | case TARGET_FREEBSD_NR_freebsd11_fstat: /* fstat(2) */ |
| 712 | ret = do_freebsd11_fstat(arg1, arg2); |
| 713 | break; |
| 714 | |
| 715 | case TARGET_FREEBSD_NR_fstat: /* fstat(2) */ |
| 716 | ret = do_freebsd_fstat(arg1, arg2); |
| 717 | break; |
| 718 | |
| 719 | case TARGET_FREEBSD_NR_freebsd11_fstatat: /* fstatat(2) */ |
| 720 | ret = do_freebsd11_fstatat(arg1, arg2, arg3, arg4); |
| 721 | break; |
| 722 | |
| 723 | case TARGET_FREEBSD_NR_fstatat: /* fstatat(2) */ |
| 724 | ret = do_freebsd_fstatat(arg1, arg2, arg3, arg4); |
| 725 | break; |
| 726 | |
| 727 | case TARGET_FREEBSD_NR_freebsd11_nstat: /* undocumented */ |
| 728 | ret = do_freebsd11_nstat(arg1, arg2); |
| 729 | break; |
| 730 | |
| 731 | case TARGET_FREEBSD_NR_freebsd11_nfstat: /* undocumented */ |
| 732 | ret = do_freebsd11_nfstat(arg1, arg2); |
| 733 | break; |
| 734 | |
| 735 | case TARGET_FREEBSD_NR_freebsd11_nlstat: /* undocumented */ |
| 736 | ret = do_freebsd11_nlstat(arg1, arg2); |
| 737 | break; |
| 738 | |
| 739 | case TARGET_FREEBSD_NR_getfh: /* getfh(2) */ |
| 740 | ret = do_freebsd_getfh(arg1, arg2); |
| 741 | break; |
| 742 | |
| 743 | case TARGET_FREEBSD_NR_lgetfh: /* lgetfh(2) */ |
| 744 | ret = do_freebsd_lgetfh(arg1, arg2); |
| 745 | break; |
| 746 | |
| 747 | case TARGET_FREEBSD_NR_fhopen: /* fhopen(2) */ |
| 748 | ret = do_freebsd_fhopen(arg1, arg2); |
| 749 | break; |
| 750 | |
| 751 | case TARGET_FREEBSD_NR_freebsd11_fhstat: /* fhstat(2) */ |
| 752 | ret = do_freebsd11_fhstat(arg1, arg2); |
| 753 | break; |
| 754 | |
| 755 | case TARGET_FREEBSD_NR_fhstat: /* fhstat(2) */ |
| 756 | ret = do_freebsd_fhstat(arg1, arg2); |
| 757 | break; |
| 758 | |
| 759 | case TARGET_FREEBSD_NR_freebsd11_fhstatfs: /* fhstatfs(2) */ |
| 760 | ret = do_freebsd11_fhstatfs(arg1, arg2); |
| 761 | break; |
| 762 | |
| 763 | case TARGET_FREEBSD_NR_fhstatfs: /* fhstatfs(2) */ |
| 764 | ret = do_freebsd_fhstatfs(arg1, arg2); |
| 765 | break; |
| 766 | |
| 767 | case TARGET_FREEBSD_NR_freebsd11_statfs: /* statfs(2) */ |
| 768 | ret = do_freebsd11_statfs(arg1, arg2); |
| 769 | break; |
| 770 | |
| 771 | case TARGET_FREEBSD_NR_statfs: /* statfs(2) */ |
| 772 | ret = do_freebsd_statfs(arg1, arg2); |
| 773 | break; |
| 774 | |
| 775 | case TARGET_FREEBSD_NR_freebsd11_fstatfs: /* fstatfs(2) */ |
| 776 | ret = do_freebsd11_fstatfs(arg1, arg2); |
| 777 | break; |
| 778 | |
| 779 | case TARGET_FREEBSD_NR_fstatfs: /* fstatfs(2) */ |
| 780 | ret = do_freebsd_fstatfs(arg1, arg2); |
| 781 | break; |
| 782 | |
| 783 | case TARGET_FREEBSD_NR_freebsd11_getfsstat: /* getfsstat(2) */ |
| 784 | ret = do_freebsd11_getfsstat(arg1, arg2, arg3); |
| 785 | break; |
| 786 | |
| 787 | case TARGET_FREEBSD_NR_getfsstat: /* getfsstat(2) */ |
| 788 | ret = do_freebsd_getfsstat(arg1, arg2, arg3); |
| 789 | break; |
| 790 | |
| 791 | case TARGET_FREEBSD_NR_freebsd11_getdents: /* getdents(2) */ |
| 792 | ret = do_freebsd11_getdents(arg1, arg2, arg3); |
| 793 | break; |
| 794 | |
| 795 | case TARGET_FREEBSD_NR_getdirentries: /* getdirentries(2) */ |
| 796 | ret = do_freebsd_getdirentries(arg1, arg2, arg3, arg4); |
| 797 | break; |
| 798 | |
| 799 | case TARGET_FREEBSD_NR_freebsd11_getdirentries: /* getdirentries(2) */ |
| 800 | ret = do_freebsd11_getdirentries(arg1, arg2, arg3, arg4); |
| 801 | break; |
| 802 | case TARGET_FREEBSD_NR_fcntl: /* fcntl(2) */ |
| 803 | ret = do_freebsd_fcntl(arg1, arg2, arg3); |
| 804 | break; |
| 805 | |
| 806 | /* |
| 807 | * Memory management system calls. |
| 808 | */ |
| 809 | case TARGET_FREEBSD_NR_mmap: /* mmap(2) */ |
| 810 | ret = do_bsd_mmap(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, |
| 811 | arg8); |
| 812 | break; |
| 813 | |
| 814 | case TARGET_FREEBSD_NR_munmap: /* munmap(2) */ |
| 815 | ret = do_bsd_munmap(arg1, arg2); |
| 816 | break; |
| 817 | |
| 818 | case TARGET_FREEBSD_NR_mprotect: /* mprotect(2) */ |
| 819 | ret = do_bsd_mprotect(arg1, arg2, arg3); |
| 820 | break; |
| 821 | |
| 822 | case TARGET_FREEBSD_NR_msync: /* msync(2) */ |
| 823 | ret = do_bsd_msync(arg1, arg2, arg3); |
| 824 | break; |
| 825 | |
| 826 | case TARGET_FREEBSD_NR_mlock: /* mlock(2) */ |
| 827 | ret = do_bsd_mlock(arg1, arg2); |
| 828 | break; |
| 829 | |
| 830 | case TARGET_FREEBSD_NR_munlock: /* munlock(2) */ |
| 831 | ret = do_bsd_munlock(arg1, arg2); |
| 832 | break; |
| 833 | |
| 834 | case TARGET_FREEBSD_NR_mlockall: /* mlockall(2) */ |
| 835 | ret = do_bsd_mlockall(arg1); |
| 836 | break; |
| 837 | |
| 838 | case TARGET_FREEBSD_NR_munlockall: /* munlockall(2) */ |
| 839 | ret = do_bsd_munlockall(); |
| 840 | break; |
| 841 | |
| 842 | case TARGET_FREEBSD_NR_madvise: /* madvise(2) */ |
| 843 | ret = do_bsd_madvise(arg1, arg2, arg3); |
| 844 | break; |
| 845 | |
| 846 | case TARGET_FREEBSD_NR_minherit: /* minherit(2) */ |
| 847 | ret = do_bsd_minherit(arg1, arg2, arg3); |
| 848 | break; |
| 849 | |
| 850 | case TARGET_FREEBSD_NR_mincore: /* mincore(2) */ |
| 851 | ret = do_bsd_mincore(arg1, arg2, arg3); |
| 852 | break; |
| 853 | |
| 854 | case TARGET_FREEBSD_NR_freebsd12_shm_open: /* shm_open(2) */ |
| 855 | ret = do_bsd_shm_open(arg1, arg2, arg3); |
| 856 | break; |
| 857 | |
| 858 | #if defined(__FreeBSD_version) && __FreeBSD_version >= 1300048 |
| 859 | case TARGET_FREEBSD_NR_shm_open2: /* shm_open2(2) */ |
| 860 | ret = do_freebsd_shm_open2(arg1, arg2, arg3, arg4, arg5); |
| 861 | break; |
| 862 | #endif |
| 863 | |
| 864 | #if defined(__FreeBSD_version) && __FreeBSD_version >= 1300049 |
| 865 | case TARGET_FREEBSD_NR_shm_rename: /* shm_rename(2) */ |
| 866 | ret = do_freebsd_shm_rename(arg1, arg2, arg3); |
| 867 | break; |
| 868 | #endif |
| 869 | |
| 870 | case TARGET_FREEBSD_NR_shm_unlink: /* shm_unlink(2) */ |
| 871 | ret = do_bsd_shm_unlink(arg1); |
| 872 | break; |
| 873 | |
| 874 | case TARGET_FREEBSD_NR_shmget: /* shmget(2) */ |
| 875 | ret = do_bsd_shmget(arg1, arg2, arg3); |
| 876 | break; |
| 877 | |
| 878 | case TARGET_FREEBSD_NR_shmctl: /* shmctl(2) */ |
| 879 | ret = do_bsd_shmctl(arg1, arg2, arg3); |
| 880 | break; |
| 881 | |
| 882 | case TARGET_FREEBSD_NR_shmat: /* shmat(2) */ |
| 883 | ret = do_bsd_shmat(arg1, arg2, arg3); |
| 884 | break; |
| 885 | |
| 886 | case TARGET_FREEBSD_NR_shmdt: /* shmdt(2) */ |
| 887 | ret = do_bsd_shmdt(arg1); |
| 888 | break; |
| 889 | |
| 890 | /* |
| 891 | * System V Semaphores |
| 892 | */ |
| 893 | case TARGET_FREEBSD_NR_semget: /* semget(2) */ |
| 894 | ret = do_bsd_semget(arg1, arg2, arg3); |
| 895 | break; |
| 896 | |
| 897 | case TARGET_FREEBSD_NR_semop: /* semop(2) */ |
| 898 | ret = do_bsd_semop(arg1, arg2, arg3); |
| 899 | break; |
| 900 | |
| 901 | case TARGET_FREEBSD_NR___semctl: { /* __semctl() undocumented */ |
| 902 | ret = do_bsd___semctl(arg1, arg2, arg3, arg4); |
| 903 | break; |
| 904 | } |
| 905 | |
| 906 | /* |
| 907 | * System V Messages |
| 908 | */ |
| 909 | case TARGET_FREEBSD_NR_msgctl: /* msgctl(2) */ |
| 910 | ret = do_bsd_msgctl(arg1, arg2, arg3); |
| 911 | break; |
| 912 | |
| 913 | case TARGET_FREEBSD_NR_msgget: /* msgget(2) */ |
| 914 | ret = do_bsd_msgget(arg1, arg2); |
| 915 | break; |
| 916 | |
| 917 | case TARGET_FREEBSD_NR_msgsnd: /* msgsnd(2) */ |
| 918 | ret = do_bsd_msgsnd(arg1, arg2, arg3, arg4); |
| 919 | break; |
| 920 | |
| 921 | case TARGET_FREEBSD_NR_msgrcv: /* msgrcv(2) */ |
| 922 | ret = do_bsd_msgrcv(arg1, arg2, arg3, arg4, arg5); |
| 923 | break; |
| 924 | |
| 925 | case TARGET_FREEBSD_NR_freebsd11_vadvise: |
| 926 | ret = do_bsd_vadvise(); |
| 927 | break; |
| 928 | |
| 929 | /* |
| 930 | * Misc |
| 931 | */ |
| 932 | case TARGET_FREEBSD_NR_break: |
| 933 | ret = do_obreak(arg1); |
| 934 | break; |
| 935 | |
| 936 | case TARGET_FREEBSD_NR_quotactl: /* quotactl(2) */ |
| 937 | ret = do_bsd_quotactl(arg1, arg2, arg3); |
| 938 | break; |
| 939 | |
| 940 | case TARGET_FREEBSD_NR_reboot: /* reboot(2) */ |
| 941 | ret = do_bsd_reboot(arg1); |
| 942 | break; |
| 943 | |
| 944 | case TARGET_FREEBSD_NR_uuidgen: /* uuidgen(2) */ |
| 945 | ret = do_bsd_uuidgen(arg1, arg2); |
| 946 | break; |
| 947 | |
| 948 | case TARGET_FREEBSD_NR_getdtablesize: /* getdtablesize(2) */ |
| 949 | ret = do_bsd_getdtablesize(); |
| 950 | break; |
| 951 | |
| 952 | /* |
| 953 | * sys{ctl, arch, call} |
| 954 | */ |
| 955 | case TARGET_FREEBSD_NR___sysctl: /* sysctl(3) */ |
| 956 | ret = do_freebsd_sysctl(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); |
| 957 | break; |
| 958 | |
| 959 | case TARGET_FREEBSD_NR___sysctlbyname: /* sysctlbyname(2) */ |
| 960 | ret = do_freebsd_sysctlbyname(cpu_env, arg1, arg2, arg3, arg4, arg5, arg6); |
| 961 | break; |
| 962 | |
| 963 | case TARGET_FREEBSD_NR_sysarch: /* sysarch(2) */ |
| 964 | ret = do_freebsd_sysarch(cpu_env, arg1, arg2); |
| 965 | break; |
| 966 | |
| 967 | default: |
| 968 | qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num); |
| 969 | ret = -TARGET_ENOSYS; |
| 970 | break; |
| 971 | } |
| 972 | |
| 973 | return ret; |
| 974 | } |
| 975 | |
| 976 | /* |
| 977 | * do_freebsd_syscall() should always have a single exit point at the end so |
| 978 | * that actions, such as logging of syscall results, can be performed. This |
| 979 | * as a wrapper around freebsd_syscall() so that actually happens. Since |
| 980 | * that is a singleton, modern compilers will inline it anyway... |
| 981 | */ |
| 982 | abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, |
| 983 | abi_long arg2, abi_long arg3, abi_long arg4, |
| 984 | abi_long arg5, abi_long arg6, abi_long arg7, |
| 985 | abi_long arg8) |
| 986 | { |
| 987 | abi_long ret; |
| 988 | |
| 989 | if (do_strace) { |
| 990 | print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); |
| 991 | } |
| 992 | |
| 993 | ret = freebsd_syscall(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6, |
| 994 | arg7, arg8); |
| 995 | if (do_strace) { |
| 996 | print_freebsd_syscall_ret(num, ret); |
| 997 | } |
| 998 | |
| 999 | return ret; |
| 1000 | } |
| 1001 | |
| 1002 | void syscall_init(void) |
| 1003 | { |
| 1004 | init_bsd_ioctl(); |
| 1005 | } |