From: Paul Floyd Date: Sat, 9 Oct 2021 12:11:48 +0000 (+0200) Subject: FreeBSD support, patch 11 X-Git-Tag: VALGRIND_3_18_0~27 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e2e5d75f5cbc108d68142c4c56878df9abaed653;p=thirdparty%2Fvalgrind.git FreeBSD support, patch 11 coregrind added files the key mechanics and the syscall wrappers --- diff --git a/configure.ac b/configure.ac index 39e619575e..275c0ca02c 100755 --- a/configure.ac +++ b/configure.ac @@ -5211,6 +5211,8 @@ AC_CONFIG_FILES([ ]) AC_CONFIG_FILES([coregrind/link_tool_exe_linux], [chmod +x coregrind/link_tool_exe_linux]) +AC_CONFIG_FILES([coregrind/link_tool_exe_freebsd], + [chmod +x coregrind/link_tool_exe_freebsd]) AC_CONFIG_FILES([coregrind/link_tool_exe_darwin], [chmod +x coregrind/link_tool_exe_darwin]) AC_CONFIG_FILES([coregrind/link_tool_exe_solaris], diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am index 01b8783ee4..1de685bb45 100644 --- a/coregrind/Makefile.am +++ b/coregrind/Makefile.am @@ -286,6 +286,7 @@ noinst_HEADERS = \ m_syswrap/priv_syswrap-generic.h \ m_syswrap/priv_syswrap-linux.h \ m_syswrap/priv_syswrap-linux-variants.h \ + m_syswrap/priv_syswrap-freebsd.h \ m_syswrap/priv_syswrap-darwin.h \ m_syswrap/priv_syswrap-solaris.h \ m_syswrap/priv_syswrap-main.h \ @@ -388,6 +389,8 @@ COREGRIND_SOURCES_COMMON = \ m_dispatch/dispatch-mips32-linux.S \ m_dispatch/dispatch-mips64-linux.S \ m_dispatch/dispatch-nanomips-linux.S \ + m_dispatch/dispatch-x86-freebsd.S \ + m_dispatch/dispatch-amd64-freebsd.S \ m_dispatch/dispatch-x86-darwin.S \ m_dispatch/dispatch-amd64-darwin.S \ m_dispatch/dispatch-x86-solaris.S \ @@ -412,6 +415,7 @@ COREGRIND_SOURCES_COMMON = \ m_gdbserver/valgrind-low-nanomips.c \ m_gdbserver/version.c \ m_initimg/initimg-linux.c \ + m_initimg/initimg-freebsd.c \ m_initimg/initimg-darwin.c \ m_initimg/initimg-solaris.c \ m_mach/mach_basics.c \ @@ -426,6 +430,8 @@ COREGRIND_SOURCES_COMMON = \ m_sigframe/sigframe-common.c \ m_sigframe/sigframe-x86-linux.c \ m_sigframe/sigframe-amd64-linux.c \ + m_sigframe/sigframe-x86-freebsd.c \ + m_sigframe/sigframe-amd64-freebsd.c \ m_sigframe/sigframe-ppc32-linux.c \ m_sigframe/sigframe-ppc64-linux.c \ m_sigframe/sigframe-arm-linux.c \ @@ -448,6 +454,8 @@ COREGRIND_SOURCES_COMMON = \ m_syswrap/syscall-mips32-linux.S \ m_syswrap/syscall-mips64-linux.S \ m_syswrap/syscall-nanomips-linux.S \ + m_syswrap/syscall-x86-freebsd.S \ + m_syswrap/syscall-amd64-freebsd.S \ m_syswrap/syscall-x86-darwin.S \ m_syswrap/syscall-amd64-darwin.S \ m_syswrap/syscall-x86-solaris.S \ @@ -456,12 +464,15 @@ COREGRIND_SOURCES_COMMON = \ m_syswrap/syswrap-generic.c \ m_syswrap/syswrap-linux.c \ m_syswrap/syswrap-linux-variants.c \ + m_syswrap/syswrap-freebsd.c \ m_syswrap/syswrap-darwin.c \ m_syswrap/syswrap-solaris.c \ m_syswrap/syswrap-x86-linux.c \ m_syswrap/syswrap-amd64-linux.c \ m_syswrap/syswrap-ppc32-linux.c \ m_syswrap/syswrap-ppc64-linux.c \ + m_syswrap/syswrap-x86-freebsd.c \ + m_syswrap/syswrap-amd64-freebsd.c \ m_syswrap/syswrap-arm-linux.c \ m_syswrap/syswrap-arm64-linux.c \ m_syswrap/syswrap-s390x-linux.c \ diff --git a/coregrind/launcher-freebsd.c b/coregrind/launcher-freebsd.c new file mode 100644 index 0000000000..7d40ad6cce --- /dev/null +++ b/coregrind/launcher-freebsd.c @@ -0,0 +1,325 @@ + +/*--------------------------------------------------------------------*/ +/*--- Launching valgrind m_launcher.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +/* Note: this is a "normal" program and not part of Valgrind proper, + and so it doesn't have to conform to Valgrind's arcane rules on + no-glibc-usage etc. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* #include */ +#include + +#include "pub_core_debuglog.h" +#include "pub_core_vki.h" // Avoids warnings from +// pub_core_libcfile.h +#include "pub_core_libcproc.h" // For VALGRIND_LIB, VALGRIND_LAUNCHER +#include "pub_core_ume.h" + + +#if !defined(PATH_MAX) +#define PATH_MAX 4096 /* POSIX refers to this a lot but I dunno + where it is defined */ +#endif + +#ifndef EM_X86_64 +#define EM_X86_64 62 // elf.h doesn't define this on some older systems +#endif + +/* Report fatal errors */ +__attribute__((noreturn)) +static void barf ( const char *format, ... ) +{ + va_list vargs; + + va_start(vargs, format); + fprintf(stderr, "valgrind: Cannot continue: "); + vfprintf(stderr, format, vargs); + fprintf(stderr, "\n"); + va_end(vargs); + + exit(1); + /*NOTREACHED*/ + assert(0); +} + +/* Search the path for the client program */ +static const char *find_client(const char *clientname) +{ + static char fullname[PATH_MAX]; + const char *path = getenv("PATH"); + const char *colon; + + while (path) { + if ((colon = strchr(path, ':')) == NULL) { + strcpy(fullname, path); + path = NULL; + } else { + memcpy(fullname, path, colon - path); + fullname[colon - path] = '\0'; + path = colon + 1; + } + + strcat(fullname, "/"); + strcat(fullname, clientname); + + if (access(fullname, R_OK|X_OK) == 0) + return fullname; + } + + return clientname; +} + +/* Examine the client and work out which platform it is for */ +static const char *select_platform(const char *clientname) +{ + int fd; + char header[4096]; + ssize_t n_bytes; + const char *platform = NULL; + + VG_(debugLog)(2, "launcher", "selecting platform for '%s'\n", clientname); + + if (strchr(clientname, '/') == NULL) + clientname = find_client(clientname); + + if ((fd = open(clientname, O_RDONLY)) < 0) + return NULL; + // barf("open(%s): %s", clientname, strerror(errno)); + + n_bytes = read(fd, header, sizeof(header)); + close(fd); + if (n_bytes < 2) { + return NULL; + } + + if (header[0] == '#' && header[1] == '!') { + int i = 2; + char *interp = (char *)header + 2; + + // Skip whitespace. + while (1) { + if (i == n_bytes) return NULL; + if (' ' != header[i] && '\t' == header[i]) break; + i++; + } + + // Get the interpreter name. + interp = &header[i]; + while (1) { + if (i == n_bytes) break; + if (isspace(header[i])) break; + i++; + } + if (i == n_bytes) return NULL; + header[i] = '\0'; + + platform = select_platform(interp); + + } else if (n_bytes >= SELFMAG && memcmp(header, ELFMAG, SELFMAG) == 0) { + + if ((size_t)n_bytes >= sizeof(Elf32_Ehdr) && header[EI_CLASS] == ELFCLASS32) { + const Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header; + + if (header[EI_DATA] == ELFDATA2LSB) { + if (ehdr->e_machine == EM_386 && + ehdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { + platform = "x86-freebsd"; + } + } + } else if ((size_t)n_bytes >= sizeof(Elf64_Ehdr) && header[EI_CLASS] == ELFCLASS64) { + const Elf64_Ehdr *ehdr = (Elf64_Ehdr *)header; + + if (header[EI_DATA] == ELFDATA2LSB) { + if (ehdr->e_machine == EM_X86_64 && + ehdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { + platform = "amd64-freebsd"; + } + } + } + } + + VG_(debugLog)(2, "launcher", "selected platform '%s'\n", + platform ? platform : "unknown"); + + return platform; +} + +/* Where we expect to find all our aux files */ +static const char *valgrind_lib = VG_LIBDIR; + +int main(int argc, char** argv, char** envp) +{ + int i, j, loglevel, r; + const char *toolname = NULL; + const char *clientname = NULL; + const char *platform; + const char *default_platform; + const char *cp; + char *toolfile; + char launcher_name[PATH_MAX+1]; + char* new_line; + char** new_env; + int oid[4]; + vki_size_t len; + + /* Start the debugging-log system ASAP. First find out how many + "-d"s were specified. This is a pre-scan of the command line. + At the same time, look for the tool name. */ + loglevel = 0; + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + clientname = argv[i]; + break; + } + if (0 == strcmp(argv[i], "--")) { + if (i+1 < argc) + clientname = argv[i+1]; + break; + } + if (0 == strcmp(argv[i], "-d")) + loglevel++; + if (0 == strncmp(argv[i], "--tool=", 7)) + toolname = argv[i] + 7; + } + + /* ... and start the debug logger. Now we can safely emit logging + messages all through startup. */ + VG_(debugLog_startup)(loglevel, "Stage 1"); + + /* Make sure we know which tool we're using */ + if (toolname) { + VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname); + } else { + VG_(debugLog)(1, "launcher", + "no tool requested, defaulting to 'memcheck'\n"); + toolname = "memcheck"; + } + + /* Select a platform to use if we can't decide that by looking at + the executable (eg because it's a shell script). Note that the + default_platform is not necessarily either the primary or + secondary build target. Instead it's chosen to maximise the + chances that /bin/sh will work on it. Hence for a primary + target of ppc64-linux we still choose ppc32-linux as the default + target, because on most ppc64-linux setups, the basic /bin, + /usr/bin, etc, stuff is built in 32-bit mode, not 64-bit + mode. */ + if (0==strcmp(VG_PLATFORM,"x86-freebsd")) + default_platform = "x86-freebsd"; + else if (0==strcmp(VG_PLATFORM,"amd64-freebsd")) + default_platform = "amd64-freebsd"; + else + barf("Unknown VG_PLATFORM '%s'", VG_PLATFORM); + + /* Work out what platform to use, or use the default platform if + not possible. */ + if (clientname == NULL) { + VG_(debugLog)(1, "launcher", + "no client specified, defaulting platform to '%s'\n", + default_platform); + platform = default_platform; + } else if ((platform = select_platform(clientname)) != NULL) { + VG_(debugLog)(1, "launcher", "selected platform '%s'\n", platform); + } else { + VG_(debugLog)(1, "launcher", + "no platform detected, defaulting platform to '%s'\n", + default_platform); + platform = default_platform; + } + + /* Figure out the name of this executable (viz, the launcher), so + we can tell stage2. stage2 will use the name for recursive + invocations of valgrind on child processes. */ + memset(launcher_name, 0, PATH_MAX+1); + + oid[0] = CTL_KERN; + oid[1] = KERN_PROC; + oid[2] = KERN_PROC_PATHNAME; + oid[3] = getpid(); + len = PATH_MAX; + r = sysctl(oid, 4, launcher_name, &len, 0, 0); + if (r != 0) { + fprintf(stderr, "valgrind: warning (non-fatal): " + "sysctl(\"kern.proc.pathname\") failed.\n"); + fprintf(stderr, "valgrind: continuing, however --trace-children=yes " + "will not work.\n"); + } + + /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */ + new_line = malloc(strlen(VALGRIND_LAUNCHER) + 1 + + strlen(launcher_name) + 1); + if (new_line == NULL) + barf("malloc of new_line failed."); + strcpy(new_line, VALGRIND_LAUNCHER); + strcat(new_line, "="); + strcat(new_line, launcher_name); + + for (j = 0; envp[j]; j++) + ; + new_env = malloc((j+2) * sizeof(char*)); + if (new_env == NULL) + barf("malloc of new_env failed."); + for (i = 0; i < j; i++) + new_env[i] = envp[i]; + new_env[i++] = new_line; + new_env[i++] = NULL; + assert(i == j+2); + + /* Establish the correct VALGRIND_LIB. */ + cp = getenv(VALGRIND_LIB); + + if (cp != NULL) + valgrind_lib = cp; + + /* Build the stage2 invocation, and execve it. Bye! */ + toolfile = malloc(strlen(valgrind_lib) + strlen(toolname) + strlen(platform) + 3); + if (toolfile == NULL) + barf("malloc of toolfile failed."); + sprintf(toolfile, "%s/%s-%s", valgrind_lib, toolname, platform); + + VG_(debugLog)(1, "launcher", "launching %s\n", toolfile); + + execve(toolfile, argv, new_env); + + fprintf(stderr, "valgrind: failed to start tool '%s' for platform '%s': %s\n", + toolname, platform, strerror(errno)); + + exit(1); +} diff --git a/coregrind/link_tool_exe_freebsd.in b/coregrind/link_tool_exe_freebsd.in new file mode 100755 index 0000000000..b4df4622c1 --- /dev/null +++ b/coregrind/link_tool_exe_freebsd.in @@ -0,0 +1,82 @@ +#! @PERL@ + +# This script handles linking the tool executables on FreeBSD, +# statically and at an alternative load address. +# +# Linking statically sidesteps all sorts of complications to do with +# having two copies of the dynamic linker (valgrind's and the +# client's) coexisting in the same process. The alternative load +# address is needed because Valgrind itself will load the client at +# whatever address it specifies, which is almost invariably the +# default load address. Hence we can't allow Valgrind itself (viz, +# the tool executable) to be loaded at that address. +# +# Unfortunately there's no standard way to do 'static link at +# alternative address', so these link_tool_exe_*.in scripts handle +# the per-platform hoop-jumping. +# +# What we get passed here is: +# first arg +# the alternative load address +# all the rest of the args +# the compiler invocation to do the final link, that +# the build system would have done, left to itself +# +# We just let the script 'die' if something is wrong, rather than do +# proper error reporting. We don't expect the users to run this +# directly. It is only run as part of the build process, with +# carefully constrained inputs. +# +# FreeBSD specific complications: +# +# - in the initial version of this file, the linker(s) it was targeted +# at supported only -Ttext to load the code at an alternative address, +# and did not require removing the build notes in order to function +# correctly, so the work done by configure to determine what should go +# into the FLAG_T_TEXT was ignored. +# +# - LLVM's ld.lld, for at least versions 8.0 (shipping with FreeBSD 12.1) +# and 9.0 support the -Ttext option and behave as desired. As of +# LLVM ld.lld version 10.0 a breaking change made -Ttext unusable, +# however the --image-base option has the desired semantics. +# It turns out that ld.lld has supported --image-base since at least +# as far back as version 8.0. +# +# So: what we actually do: +# +# pass the specified command to the linker as-is, except, add +# "-static" and the value of FLAG_T_TEXT as determined by configure. +# Previously we did this by adding these options after the first +# word of the rest of the arguments, which works in the common case +# when it's something like "gcc". But the linker invocation itself +# might be multiple words, say if it's "ccache gcc". So we now put +# the new options at the end instead. +# + +use warnings; +use strict; + +# expect at least: alt-load-address gcc -o foo bar.o +die "Not enough arguments" + if (($#ARGV + 1) < 5); + +my $ala = $ARGV[0]; +shift; # Remove $ala from @ARGV + +# check for plausible-ish alt load address +die "Bogus alt-load address" + if (length($ala) < 3 || index($ala, "0x") != 0); + +my $cmd = join(" ", @ARGV, "-static -Wl,@FLAG_T_TEXT@=$ala"); + +#print "link_tool_exe_freebsd: $cmd\n"; + + +# Execute the command: +my $r = system("$cmd"); + +if ($r == 0) { + exit 0; +} else { + exit 1; +} diff --git a/coregrind/m_dispatch/dispatch-amd64-freebsd.S b/coregrind/m_dispatch/dispatch-amd64-freebsd.S new file mode 100644 index 0000000000..db4dccac76 --- /dev/null +++ b/coregrind/m_dispatch/dispatch-amd64-freebsd.S @@ -0,0 +1,321 @@ + +/*--------------------------------------------------------------------*/ +/*--- The core dispatch loop, for jumping to a code address. ---*/ +/*--- dispatch-amd64-freebsd.S ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2017 Julian Seward + jseward@acm.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#include "pub_core_basics_asm.h" + +#if defined(VGP_amd64_freebsd) + +#include "pub_core_dispatch_asm.h" +#include "pub_core_transtab_asm.h" +#include "libvex_guest_offsets.h" /* for OFFSET_amd64_RIP */ + + +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- The dispatch loop. VG_(disp_run_translations) is ---*/ +/*--- used to run all translations, ---*/ +/*--- including no-redir ones. ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ + +/*----------------------------------------------------*/ +/*--- Entry and preamble (set everything up) ---*/ +/*----------------------------------------------------*/ + +/* signature: +void VG_(disp_run_translations)( UWord* two_words, + void* guest_state, + Addr host_addr ); +*/ +.text +.globl VG_(disp_run_translations) +.type VG_(disp_run_translations), @function +VG_(disp_run_translations): + /* %rdi holds two_words */ + /* %rsi holds guest_state */ + /* %rdx holds host_addr */ + + /* The preamble */ + + /* Save integer registers, since this is a pseudo-function. */ + pushq %rax + pushq %rbx + pushq %rcx + pushq %rdx + pushq %rsi + pushq %rbp + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + /* %rdi must be saved last */ + pushq %rdi + + /* Get the host CPU in the state expected by generated code. */ + + /* set host FPU control word to the default mode expected + by VEX-generated code. See comments in libvex.h for + more info. */ + finit + pushq $0x027F + fldcw (%rsp) + addq $8, %rsp + + /* set host SSE control word to the default mode expected + by VEX-generated code. */ + pushq $0x1F80 + ldmxcsr (%rsp) + addq $8, %rsp + + /* set dir flag to known value */ + cld + + /* Set up the guest state pointer */ + movq %rsi, %rbp + + /* and jump into the code cache. Chained translations in + the code cache run, until for whatever reason, they can't + continue. When that happens, the translation in question + will jump (or call) to one of the continuation points + VG_(cp_...) below. */ + jmpq *%rdx + /*NOTREACHED*/ + +/*----------------------------------------------------*/ +/*--- Postamble and exit. ---*/ +/*----------------------------------------------------*/ + +postamble: + /* At this point, %rax and %rdx contain two + words to be returned to the caller. %rax + holds a TRC value, and %rdx optionally may + hold another word (for CHAIN_ME exits, the + address of the place to patch.) */ + + /* We're leaving. Check that nobody messed with %mxcsr + or %fpucw. We can't mess with %rax or %rdx here as they + hold the tentative return values, but any others are OK. */ +#if !defined(ENABLE_INNER) + /* This check fails for self-hosting, so skip in that case */ + pushq $0 + fstcw (%rsp) + cmpl $0x027F, (%rsp) + popq %r15 /* get rid of the word without trashing %rflags */ + jnz invariant_violation +#endif + pushq $0 + stmxcsr (%rsp) + andl $0xFFFFFFC0, (%rsp) /* mask out status flags */ + cmpl $0x1F80, (%rsp) + popq %r15 + jnz invariant_violation + /* otherwise we're OK */ + jmp remove_frame +invariant_violation: + movq $VG_TRC_INVARIANT_FAILED, %rax + movq $0, %rdx + +remove_frame: + /* Pop %rdi, stash return values */ + popq %rdi + movq %rax, 0(%rdi) + movq %rdx, 8(%rdi) + /* Now pop everything else */ + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rbp + popq %rsi + popq %rdx + popq %rcx + popq %rbx + popq %rax + ret + +/*----------------------------------------------------*/ +/*--- Continuation points ---*/ +/*----------------------------------------------------*/ + +/* ------ Chain me to slow entry point ------ */ +.global VG_(disp_cp_chain_me_to_slowEP) +VG_(disp_cp_chain_me_to_slowEP): + /* We got called. The return address indicates + where the patching needs to happen. Collect + the return address and, exit back to C land, + handing the caller the pair (Chain_me_S, RA) */ + movq $VG_TRC_CHAIN_ME_TO_SLOW_EP, %rax + popq %rdx + /* 10 = movabsq $VG_(disp_chain_me_to_slowEP), %r11; + 3 = call *%r11 */ + subq $10+3, %rdx + jmp postamble + +/* ------ Chain me to fast entry point ------ */ +.global VG_(disp_cp_chain_me_to_fastEP) +VG_(disp_cp_chain_me_to_fastEP): + /* We got called. The return address indicates + where the patching needs to happen. Collect + the return address and, exit back to C land, + handing the caller the pair (Chain_me_F, RA) */ + movq $VG_TRC_CHAIN_ME_TO_FAST_EP, %rax + popq %rdx + /* 10 = movabsq $VG_(disp_chain_me_to_fastEP), %r11; + 3 = call *%r11 */ + subq $10+3, %rdx + jmp postamble + +/* ------ Indirect but boring jump ------ */ +.global VG_(disp_cp_xindir) +VG_(disp_cp_xindir): + /* Where are we going? */ + movq OFFSET_amd64_RIP(%rbp), %rax // "guest" + + /* stats only */ + addl $1, VG_(stats__n_xIndirs_32) + + // LIVE: %rbp (guest state ptr), %rax (guest address to go to). + // We use 4 temporaries: + // %r9 (to point at the relevant FastCacheSet), + // %r10, %r11 and %r12 (scratch). + + /* Try a fast lookup in the translation cache. This is pretty much + a handcoded version of VG_(lookupInFastCache). */ + + // Compute %r9 = VG_TT_FAST_HASH(guest) + movq %rax, %r9 // guest + shrq $VG_TT_FAST_BITS, %r9 // (guest >> VG_TT_FAST_BITS) + xorq %rax, %r9 // (guest >> VG_TT_FAST_BITS) ^ guest + andq $VG_TT_FAST_MASK, %r9 // setNo + + // Compute %r9 = &VG_(tt_fast)[%r9] + shlq $VG_FAST_CACHE_SET_BITS, %r9 // setNo * sizeof(FastCacheSet) + movabsq $VG_(tt_fast), %r10 // &VG_(tt_fast)[0] + leaq (%r10, %r9), %r9 // &VG_(tt_fast)[setNo] + + // LIVE: %rbp (guest state ptr), %rax (guest addr), %r9 (cache set) + // try way 0 + cmpq %rax, FCS_g0(%r9) // cmp against .guest0 + jnz 1f + // hit at way 0 + jmp *FCS_h0(%r9) // goto .host0 + ud2 + +1: // try way 1 + cmpq %rax, FCS_g1(%r9) // cmp against .guest1 + jnz 2f + // hit at way 1; swap upwards + /* stats only */ + addl $1, VG_(stats__n_xIndir_hits1_32) + movq FCS_g0(%r9), %r10 // r10 = old .guest0 + movq FCS_h0(%r9), %r11 // r11 = old .host0 + movq FCS_h1(%r9), %r12 // r12 = old .host1 + movq %rax, FCS_g0(%r9) // new .guest0 = guest + movq %r12, FCS_h0(%r9) // new .host0 = old .host1 + movq %r10, FCS_g1(%r9) // new .guest1 = old .guest0 + movq %r11, FCS_h1(%r9) // new .host1 = old .host0 + jmp *%r12 // goto old .host1 a.k.a. new .host0 + ud2 + +2: // try way 2 + cmpq %rax, FCS_g2(%r9) // cmp against .guest2 + jnz 3f + // hit at way 2; swap upwards + /* stats only */ + addl $1, VG_(stats__n_xIndir_hits2_32) + movq FCS_g1(%r9), %r10 + movq FCS_h1(%r9), %r11 + movq FCS_h2(%r9), %r12 + movq %rax, FCS_g1(%r9) + movq %r12, FCS_h1(%r9) + movq %r10, FCS_g2(%r9) + movq %r11, FCS_h2(%r9) + jmp *%r12 + ud2 + +3: // try way 3 + cmpq %rax, FCS_g3(%r9) // cmp against .guest3 + jnz 4f + // hit at way 3; swap upwards + /* stats only */ + addl $1, VG_(stats__n_xIndir_hits3_32) + movq FCS_g2(%r9), %r10 + movq FCS_h2(%r9), %r11 + movq FCS_h3(%r9), %r12 + movq %rax, FCS_g2(%r9) + movq %r12, FCS_h2(%r9) + movq %r10, FCS_g3(%r9) + movq %r11, FCS_h3(%r9) + jmp *%r12 + ud2 + +4: // fast lookup failed + /* stats only */ + addl $1, VG_(stats__n_xIndir_misses_32) + + movq $VG_TRC_INNER_FASTMISS, %rax + movq $0, %rdx + jmp postamble + +/* ------ Assisted jump ------ */ +.global VG_(disp_cp_xassisted) +VG_(disp_cp_xassisted): + /* %rbp contains the TRC */ + movq %rbp, %rax + movq $0, %rdx + jmp postamble + +/* ------ Event check failed ------ */ +.global VG_(disp_cp_evcheck_fail) +VG_(disp_cp_evcheck_fail): + movq $VG_TRC_INNER_COUNTERZERO, %rax + movq $0, %rdx + jmp postamble + + +.size VG_(disp_run_translations), .-VG_(disp_run_translations) + +#endif // defined(VGP_amd64_freebsd) + +/* Let the linker know we don't need an executable stack */ +MARK_STACK_NO_EXEC + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_dispatch/dispatch-x86-freebsd.S b/coregrind/m_dispatch/dispatch-x86-freebsd.S new file mode 100644 index 0000000000..667bfcd96a --- /dev/null +++ b/coregrind/m_dispatch/dispatch-x86-freebsd.S @@ -0,0 +1,251 @@ + +/*--------------------------------------------------------------------*/ +/*--- The core dispatch loop, for jumping to a code address. ---*/ +/*--- dispatch-x86-freebsd.S ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2012 Julian Seward + jseward@acm.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#include "pub_core_basics_asm.h" + +#if defined(VGP_x86_freebsd) + +#include "pub_core_dispatch_asm.h" +#include "pub_core_transtab_asm.h" +#include "libvex_guest_offsets.h" /* for OFFSET_x86_EIP */ + + +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- The dispatch loop. VG_(disp_run_translations) is ---*/ +/*--- used to run all translations, ---*/ +/*--- including no-redir ones. ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ + +/*----------------------------------------------------*/ +/*--- Entry and preamble (set everything up) ---*/ +/*----------------------------------------------------*/ + +/* signature: +void VG_(disp_run_translations)( UWord* two_words, + void* guest_state, + Addr host_addr ); +*/ +.text +.globl VG_(disp_run_translations) +.type VG_(disp_run_translations), @function +VG_(disp_run_translations): + /* 0(%esp) holds our return address. */ + /* 4(%esp) holds two_words */ + /* 8(%esp) holds guest_state */ + /* 12(%esp) holds host_addr */ + + /* The preamble */ + + /* Save integer registers, since this is a pseudo-function. */ + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + pushl %ebp + + /* 28+4(%esp) holds two_words */ + /* 28+8(%esp) holds guest_state */ + /* 28+12(%esp) holds host_addr */ + + /* Get the host CPU in the state expected by generated code. */ + + /* set host FPU control word to the default mode expected + by VEX-generated code. See comments in libvex.h for + more info. */ + finit + pushl $0x027F + fldcw (%esp) + addl $4, %esp + + /* set host SSE control word to the default mode expected + by VEX-generated code. */ + cmpl $0, VG_(machine_x86_have_mxcsr) + jz L1 + pushl $0x1F80 + ldmxcsr (%esp) + addl $4, %esp +L1: + /* set dir flag to known value */ + cld + + /* Set up the guest state pointer */ + movl 28+8(%esp), %ebp + + /* and jump into the code cache. Chained translations in + the code cache run, until for whatever reason, they can't + continue. When that happens, the translation in question + will jump (or call) to one of the continuation points + VG_(cp_...) below. */ + jmpl *28+12(%esp) + /*NOTREACHED*/ + +/*----------------------------------------------------*/ +/*--- Postamble and exit. ---*/ +/*----------------------------------------------------*/ + +postamble: + /* At this point, %eax and %edx contain two + words to be returned to the caller. %eax + holds a TRC value, and %edx optionally may + hold another word (for CHAIN_ME exits, the + address of the place to patch.) */ + + /* We're leaving. Check that nobody messed with %mxcsr + or %fpucw. We can't mess with %eax or %edx here as they + holds the tentative return value, but any others are OK. */ +#if !defined(ENABLE_INNER) + /* This check fails for self-hosting, so skip in that case */ + pushl $0 + fstcw (%esp) + cmpl $0x027F, (%esp) + popl %esi /* get rid of the word without trashing %eflags */ + jnz invariant_violation +#endif +# cmpl $0, VG_(machine_x86_have_mxcsr) + jz L2 + pushl $0 + stmxcsr (%esp) + andl $0xFFFFFFC0, (%esp) /* mask out status flags */ + cmpl $0x1F80, (%esp) + popl %esi + jnz invariant_violation +L2: /* otherwise we're OK */ + jmp remove_frame +invariant_violation: + movl $VG_TRC_INVARIANT_FAILED, %eax + movl $0, %edx + +remove_frame: + /* Stash return values */ + movl 28+4(%esp), %edi /* two_words */ + movl %eax, 0(%edi) + movl %edx, 4(%edi) + /* Restore int regs and return. */ + popl %ebp + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + ret + +/*----------------------------------------------------*/ +/*--- Continuation points ---*/ +/*----------------------------------------------------*/ + +/* ------ Chain me to slow entry point ------ */ +.global VG_(disp_cp_chain_me_to_slowEP) +VG_(disp_cp_chain_me_to_slowEP): + /* We got called. The return address indicates + where the patching needs to happen. Collect + the return address and, exit back to C land, + handing the caller the pair (Chain_me_S, RA) */ + movl $VG_TRC_CHAIN_ME_TO_SLOW_EP, %eax + popl %edx + /* 5 = movl $VG_(disp_chain_me_to_slowEP), %edx; + 2 = call *%edx */ + subl $5+2, %edx + jmp postamble + +/* ------ Chain me to fast entry point ------ */ +.global VG_(disp_cp_chain_me_to_fastEP) +VG_(disp_cp_chain_me_to_fastEP): + /* We got called. The return address indicates + where the patching needs to happen. Collect + the return address and, exit back to C land, + handing the caller the pair (Chain_me_F, RA) */ + movl $VG_TRC_CHAIN_ME_TO_FAST_EP, %eax + popl %edx + /* 5 = movl $VG_(disp_chain_me_to_fastEP), %edx; + 2 = call *%edx */ + subl $5+2, %edx + jmp postamble + +/* ------ Indirect but boring jump ------ */ +.global VG_(disp_cp_xindir) +VG_(disp_cp_xindir): + /* Where are we going? */ + movl OFFSET_x86_EIP(%ebp), %eax + + /* stats only */ + addl $1, VG_(stats__n_xIndirs_32) + + /* try a fast lookup in the translation cache */ + movl %eax, %ebx /* next guest addr */ + andl $VG_TT_FAST_MASK, %ebx /* entry# */ + movl 0+VG_(tt_fast)(,%ebx,8), %esi /* .guest */ + movl 4+VG_(tt_fast)(,%ebx,8), %edi /* .host */ + cmpl %eax, %esi + jnz fast_lookup_failed + + /* Found a match. Jump to .host. */ + jmp *%edi + ud2 /* persuade insn decoders not to speculate past here */ + +fast_lookup_failed: + /* stats only */ + addl $1, VG_(stats__n_xIndir_misses_32) + + movl $VG_TRC_INNER_FASTMISS, %eax + movl $0, %edx + jmp postamble + +/* ------ Assisted jump ------ */ +.global VG_(disp_cp_xassisted) +VG_(disp_cp_xassisted): + /* %ebp contains the TRC */ + movl %ebp, %eax + movl $0, %edx + jmp postamble + +/* ------ Event check failed ------ */ +.global VG_(disp_cp_evcheck_fail) +VG_(disp_cp_evcheck_fail): + movl $VG_TRC_INNER_COUNTERZERO, %eax + movl $0, %edx + jmp postamble + + +.size VG_(disp_run_translations), .-VG_(disp_run_translations) + +#endif // defined(VGP_x86_freebsd) + +/* Let the linker know we don't need an executable stack */ +MARK_STACK_NO_EXEC + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_initimg/initimg-freebsd.c b/coregrind/m_initimg/initimg-freebsd.c new file mode 100644 index 0000000000..d19186a42c --- /dev/null +++ b/coregrind/m_initimg/initimg-freebsd.c @@ -0,0 +1,979 @@ + +/*--------------------------------------------------------------------*/ +/*--- Startup: create initial process image on FreeBSD ---*/ +/*--- initimg-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGO_freebsd) + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_debuglog.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcfile.h" +#include "pub_core_libcproc.h" +#include "pub_core_libcprint.h" +#include "pub_core_xarray.h" +#include "pub_core_clientstate.h" +#include "pub_core_aspacemgr.h" +#include "pub_core_mallocfree.h" +#include "pub_core_machine.h" +#include "pub_core_ume.h" +#include "pub_core_options.h" +#include "pub_core_syscall.h" +#include "pub_core_tooliface.h" /* VG_TRACK */ +#include "pub_core_threadstate.h" /* ThreadArchState */ +#include "pub_core_pathscan.h" +#include "pub_core_initimg.h" /* self */ + +/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ +/* This is for ELF types etc, and also the AT_ constants. */ +#include +/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */ + + +/*====================================================================*/ +/*=== Loading the client ===*/ +/*====================================================================*/ + +/* Load the client whose name is VG_(argv_the_exename). */ + +static void load_client ( /*OUT*/ExeInfo* info, + /*OUT*/Addr* client_ip, + /*OUT*/Addr* client_toc) +{ + const HChar* exe_name; + Int ret; + SysRes res; + + vg_assert( VG_(args_the_exename) != NULL); + exe_name = VG_(find_executable)( VG_(args_the_exename) ); + + if (!exe_name) { + VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename)); + VG_(exit)(127); // 127 is Posix NOTFOUND + } + + VG_(memset)(info, 0, sizeof(*info)); + ret = VG_(do_exec)(exe_name, info); + if (ret < 0) { + VG_(printf)("valgrind: could not execute '%s'\n", exe_name); + VG_(exit)(1); + } + + // The client was successfully loaded! Continue. + + /* Get hold of a file descriptor which refers to the client + executable. This is needed for attaching to GDB. */ + res = VG_(open)(exe_name, VKI_O_RDONLY, VKI_S_IRUSR); + if (!sr_isError(res)) + VG_(cl_exec_fd) = sr_Res(res); + + /* Copy necessary bits of 'info' that were filled in */ + *client_ip = info->init_ip; + *client_toc = info->init_toc; + VG_(brk_base) = VG_(brk_limit) = VG_PGROUNDUP(info->brkbase); +} + + +/*====================================================================*/ +/*=== Setting up the client's environment ===*/ +/*====================================================================*/ + +/* Prepare the client's environment. This is basically a copy of our + environment, except: + + LD_PRELOAD=$VALGRIND_LIB/vgpreload_core-PLATFORM.so: + ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)? + $LD_PRELOAD + + If this is missing, then it is added. + + Also, remove any binding for VALGRIND_LAUNCHER=. The client should + not be able to see this. + + If this needs to handle any more variables it should be hacked + into something table driven. The copy is VG_(malloc)'d space. +*/ +static HChar** setup_client_env ( HChar** origenv, const HChar* toolname) +{ + vg_assert(origenv); + vg_assert(toolname); + + const HChar* preload_core = "vgpreload_core"; + const HChar* ld_preload = "LD_PRELOAD="; + const HChar* v_launcher = VALGRIND_LAUNCHER "="; + Int ld_preload_len = VG_(strlen)( ld_preload ); + Int v_launcher_len = VG_(strlen)( v_launcher ); + Bool ld_preload_done = False; +#if defined(VGP_x86_freebsd) + const HChar* ld_32_preload = "LD_32_PRELOAD="; + Int ld_32_preload_len = VG_(strlen)( ld_32_preload ); + Bool ld_32_preload_done = False; +#endif + Int vglib_len = VG_(strlen)(VG_(libdir)); + Bool debug = False; + + HChar** cpp; + HChar** ret; + HChar* preload_tool_path; + Int envc, i; + + /* Alloc space for the vgpreload_core.so path and vgpreload_.so + paths. We might not need the space for vgpreload_.so, but it + doesn't hurt to over-allocate briefly. The 16s are just cautious + slop. */ + Int preload_core_path_len = vglib_len + sizeof(preload_core) + + sizeof(VG_PLATFORM) + 16; + Int preload_tool_path_len = vglib_len + VG_(strlen)(toolname) + + sizeof(VG_PLATFORM) + 16; + Int preload_string_len = preload_core_path_len + preload_tool_path_len; + HChar* preload_string = VG_(malloc)("initimg-freebsd.sce.1", + preload_string_len); + /* Determine if there's a vgpreload__.so file, and setup + preload_string. */ + preload_tool_path = VG_(malloc)("initimg-freebsd.sce.2", preload_tool_path_len); + VG_(snprintf)(preload_tool_path, preload_tool_path_len, + "%s/vgpreload_%s-%s.so", VG_(libdir), toolname, VG_PLATFORM); + if (VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/) == 0) { + VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so:%s", + VG_(libdir), preload_core, VG_PLATFORM, preload_tool_path); + } else { + VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so", + VG_(libdir), preload_core, VG_PLATFORM); + } + VG_(free)(preload_tool_path); + + VG_(debugLog)(2, "initimg", "preload_string:\n"); + VG_(debugLog)(2, "initimg", " \"%s\"\n", preload_string); + + /* Count the original size of the env */ + if (debug) VG_(printf)("\n\n"); + envc = 0; + for (cpp = origenv; cpp && *cpp; cpp++) { + envc++; + if (debug) VG_(printf)("XXXXXXXXX: BEFORE %s\n", *cpp); + } + + /* Allocate a new space */ + ret = VG_(malloc) ("initimg-freebsd.sce.3", + sizeof(HChar *) * (envc+2+1)); /* 2 new entries + NULL */ + + /* copy it over */ + for (cpp = ret; *origenv; ) { + if (debug) VG_(printf)("XXXXXXXXX: COPY %s\n", *origenv); + *cpp++ = *origenv++; + } + *cpp = NULL; + *(cpp + 1) = NULL; + + vg_assert(envc == (cpp - ret)); + + /* Walk over the new environment, mashing as we go */ + for (cpp = ret; cpp && *cpp; cpp++) { + if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len) == 0) { + Int len = VG_(strlen)(*cpp) + preload_string_len; + HChar *cp = VG_(malloc)("initimg-freebsd.sce.4", len); + + VG_(snprintf)(cp, len, "%s%s:%s", + ld_preload, preload_string, (*cpp)+ld_preload_len); + + *cpp = cp; + + ld_preload_done = True; + } + if (debug) VG_(printf)("XXXXXXXXX: MASH %s\n", *cpp); + } + + /* Add the missing bits */ + if (!ld_preload_done) { + Int len = ld_preload_len + preload_string_len; + HChar *cp = VG_(malloc) ("initimg-freebsd.sce.5", len); + + VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string); + + ret[envc++] = cp; + if (debug) VG_(printf)("XXXXXXXXX: ADD %s\n", cp); + } + +#if defined(VGP_x86_freebsd) + /* If we're running a 32 bit binary, ld-elf32.so.1 may be looking for + * a different variable name. Or it might be a 32 bit ld-elf.so.1 in a + * chroot. Cover both cases. */ + if (VG_(is32on64)()) { + for (cpp = ret; cpp && *cpp; cpp++) { + if (VG_(memcmp)(*cpp, ld_32_preload, ld_32_preload_len) == 0) { + Int len = VG_(strlen)(*cpp) + preload_string_len; + HChar *cp = VG_(malloc)("initimg-freebsd.sce.4a", len); + vg_assert(cp); + + VG_(snprintf)(cp, len, "%s%s:%s", + ld_32_preload, preload_string, (*cpp)+ld_32_preload_len); + + *cpp = cp; + + ld_32_preload_done = True; + } + } + if (!ld_32_preload_done) { + Int len = ld_32_preload_len + preload_string_len; + HChar *cp = VG_(malloc) ("initimg-freebsd.sce.5a", len); + vg_assert(cp); + + VG_(snprintf)(cp, len, "%s%s", ld_32_preload, preload_string); + + ret[envc++] = cp; + } + } +#endif + + /* ret[0 .. envc-1] is live now. */ + /* Find and remove a binding for VALGRIND_LAUNCHER. */ + for (i = 0; i < envc; i++) + if (0 == VG_(memcmp)(ret[i], v_launcher, v_launcher_len)) + break; + + if (i < envc) { + for (; i < envc-1; i++) + ret[i] = ret[i+1]; + envc--; + } + + VG_(free)(preload_string); + ret[envc] = NULL; + + for (i = 0; i < envc; i++) { + if (debug) VG_(printf)("XXXXXXXXX: FINAL %s\n", ret[i]); + } + + return ret; +} + + +/*====================================================================*/ +/*=== Setting up the client's stack ===*/ +/*====================================================================*/ + +/* Add a string onto the string table, and return its address */ +static HChar *copy_str(HChar **tab, const HChar *str) +{ + HChar *cp = *tab; + HChar *orig = cp; + + while(*str) + *cp++ = *str++; + *cp++ = '\0'; + + if (0) + VG_(printf)("copied %p \"%s\" len %lld\n", (void*)orig, orig, (Long)(cp-orig)); + + *tab = cp; + + return orig; +} + + +/* ---------------------------------------------------------------- + + This sets up the client's initial stack, containing the args, + environment and aux vector. + + The format of the stack is: + + higher address +-----------------+ <- clstack_end + | | + : string table : + | | + +-----------------+ + | AT_NULL | + - - + | auxv | + +-----------------+ + | NULL | + - - + | envp | + +-----------------+ + | NULL | + - - + | argv | + +-----------------+ + | argc | + lower address +-----------------+ <- sp + | undefined | + : : + + Allocate and create the initial client stack. It is allocated down + from clstack_end, which was previously determined by the address + space manager. The returned value is the SP value for the client. + + The client's auxv is created by copying and modifying our own one. + + ---------------------------------------------------------------- */ + +struct auxv { + Word a_type; + union { + void *a_ptr; + Word a_val; + } u; +}; + +static +struct auxv *find_auxv(UWord* sp) +{ + sp++; // skip argc (Nb: is word-sized, not int-sized!) + + while (*sp != 0) // skip argv + sp++; + sp++; + + while (*sp != 0) // skip env + sp++; + sp++; + + return (struct auxv *)sp; +} + +static +Addr setup_client_stack( void* init_sp, + HChar** orig_envp, + const ExeInfo* info, + UInt** client_auxv, + Addr clstack_end, + SizeT clstack_max_size ) +{ + SysRes res; + HChar **cpp; + HChar *strtab; /* string table */ + HChar *stringbase; + Addr *ptr; + struct auxv *auxv; + const struct auxv *orig_auxv; + const struct auxv *cauxv; + unsigned stringsize; /* total size of strings in bytes */ + unsigned auxsize; /* total size of auxv in bytes */ + Int argc; /* total argc */ + Int envc; /* total number of env vars */ + unsigned stacksize; /* total client stack size */ + Addr client_SP; /* client stack base (initial SP) */ + Addr clstack_start; + Int i; + Bool have_exename; + + vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1)); + vg_assert( VG_(args_for_client) ); + + /* use our own auxv as a prototype */ + orig_auxv = find_auxv(init_sp); + + /* ==================== compute sizes ==================== */ + + /* first of all, work out how big the client stack will be */ + stringsize = 0; + have_exename = VG_(args_the_exename) != NULL; + + /* paste on the extra args if the loader needs them (ie, the #! + interpreter and its argument) */ + argc = 0; + if (info->interp_name != NULL) { + argc++; + stringsize += VG_(strlen)(info->interp_name) + 1; + } + if (info->interp_args != NULL) { + argc++; + stringsize += VG_(strlen)(info->interp_args) + 1; + } + + /* now scan the args we're given... */ + if (have_exename) + stringsize += VG_(strlen)( VG_(args_the_exename) ) + 1; + + for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) { + argc++; + stringsize += VG_(strlen)( * (HChar**) + VG_(indexXA)( VG_(args_for_client), i )) + + 1; + } + + /* ...and the environment */ + envc = 0; + for (cpp = orig_envp; cpp && *cpp; cpp++) { + envc++; + stringsize += VG_(strlen)(*cpp) + 1; + } + + /* now, how big is the auxv? */ + auxsize = sizeof(*auxv); /* there's always at least one entry: AT_NULL */ + for (cauxv = orig_auxv; cauxv->a_type != AT_NULL; cauxv++) { + auxsize += sizeof(*cauxv); + } + + /* OK, now we know how big the client stack is */ + stacksize = + sizeof(Word) + /* argc */ + (have_exename ? sizeof(HChar **) : 0) + /* argc[0] == exename */ + sizeof(HChar **)*argc + /* argv */ + sizeof(HChar **) + /* terminal NULL */ + sizeof(HChar **)*envc + /* envp */ + sizeof(HChar **) + /* terminal NULL */ + auxsize + /* auxv */ + VG_ROUNDUP(stringsize, sizeof(Word)); /* strings (aligned) */ + + if (0) VG_(printf)("stacksize = %u\n", stacksize); + + /* client_SP is the client's stack pointer */ + client_SP = clstack_end - stacksize; + client_SP = VG_ROUNDDN(client_SP, 16); /* make stack 16 byte aligned */ + + /* base of the string table (aligned) */ + stringbase = strtab = (HChar *)clstack_end + - VG_ROUNDUP(stringsize, sizeof(int)); + + clstack_start = VG_PGROUNDDN(client_SP); + + /* The max stack size */ + clstack_max_size = VG_PGROUNDUP(clstack_max_size); + + if (0) + VG_(printf)("stringsize=%u auxsize=%u stacksize=%u maxsize=0x%lx\n" + "clstack_start %p\n" + "clstack_end %p\n", + stringsize, auxsize, stacksize, clstack_max_size, + (void*)clstack_start, (void*)clstack_end); + + /* ==================== allocate space ==================== */ + + { + SizeT anon_size = clstack_end - clstack_start + 1; + SizeT resvn_size = clstack_max_size - anon_size; + Addr anon_start = clstack_start; + Addr resvn_start = anon_start - resvn_size; + SizeT inner_HACK = 0; + Bool ok; + + /* So far we've only accounted for space requirements down to the + stack pointer. If this target's ABI requires a redzone below + the stack pointer, we need to allocate an extra page, to + handle the worst case in which the stack pointer is almost at + the bottom of a page, and so there is insufficient room left + over to put the redzone in. In this case the simple thing to + do is allocate an extra page, by shrinking the reservation by + one page and growing the anonymous area by a corresponding + page. */ + vg_assert(VG_STACK_REDZONE_SZB >= 0); + vg_assert(VG_STACK_REDZONE_SZB < VKI_PAGE_SIZE); + if (VG_STACK_REDZONE_SZB > 0) { + vg_assert(resvn_size > VKI_PAGE_SIZE); + resvn_size -= VKI_PAGE_SIZE; + anon_start -= VKI_PAGE_SIZE; + anon_size += VKI_PAGE_SIZE; + } + + vg_assert(VG_IS_PAGE_ALIGNED(anon_size)); + vg_assert(VG_IS_PAGE_ALIGNED(resvn_size)); + vg_assert(VG_IS_PAGE_ALIGNED(anon_start)); + vg_assert(VG_IS_PAGE_ALIGNED(resvn_start)); + vg_assert(resvn_start == clstack_end + 1 - clstack_max_size); + +# ifdef ENABLE_INNER + inner_HACK = 1024*1024; // create 1M non-fault-extending stack +# endif + + if (0) + VG_(printf)("%#lx 0x%lx %#lx 0x%lx\n", + resvn_start, resvn_size, anon_start, anon_size); + + /* Create a shrinkable reservation followed by an anonymous + segment. Together these constitute a growdown stack. */ + res = VG_(mk_SysRes_Error)(0); + ok = VG_(am_create_reservation)( + resvn_start, + resvn_size -inner_HACK, + SmUpper, + anon_size +inner_HACK + ); + if (ok) { + /* allocate a stack - mmap enough space for the stack */ + res = VG_(am_mmap_anon_fixed_client)( + anon_start -inner_HACK, + anon_size +inner_HACK, + VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC + ); + } + if ((!ok) || sr_isError(res)) { + /* Allocation of the stack failed. We have to stop. */ + VG_(printf)("valgrind: " + "I failed to allocate space for the application's stack.\n"); + VG_(printf)("valgrind: " + "This may be the result of a very large --main-stacksize=\n"); + VG_(printf)("valgrind: setting. Cannot continue. Sorry.\n\n"); + VG_(exit)(1); + } + + vg_assert(ok); + vg_assert(!sr_isError(res)); + + /* Record stack extent -- needed for stack-change code. */ + VG_(clstk_start_base) = anon_start -inner_HACK; + VG_(clstk_end) = VG_(clstk_start_base) + anon_size +inner_HACK -1; + + } + + /* ==================== create client stack ==================== */ + + ptr = (Addr*)client_SP; + + /* --- client argc --- */ + *ptr++ = argc + (have_exename ? 1 : 0); + + /* --- client argv --- */ + if (info->interp_name) + *ptr++ = (Addr)copy_str(&strtab, info->interp_name); + if (info->interp_args) + *ptr++ = (Addr)copy_str(&strtab, info->interp_args); + + if (have_exename) + *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename)); + + for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) { + *ptr++ = (Addr)copy_str( + &strtab, + * (HChar**) VG_(indexXA)( VG_(args_for_client), i ) + ); + } + *ptr++ = 0; + + /* --- envp --- */ + VG_(client_envp) = (HChar **)ptr; + for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++) + *ptr = (Addr)copy_str(&strtab, *cpp); + *ptr++ = 0; + + /* --- auxv --- */ + auxv = (struct auxv *)ptr; + *client_auxv = (UInt *)auxv; +#if defined(VGP_x86_freebsd) + int* pagesizes = NULL; +#endif + + /* + * The PAGESIZES hack - PJF + * + * Normally a standalone application has a full auxv which, among + * many other things contains a vector of integers (PAGESIZES) + * of a platform dependent length (PAGESIZESLEN). On x86 the + * length is 2, on amd64 the length is 3 (there are other lengths + * for architectures not supported on Valgrind). + * + * When the dynamic loader executes it will run a routine + * static void init_pagesizes(Elf_Auxinfo **aux_info) + * (see /usr/src/libexec/rtld-elf/rltd.c). If the PAGESIZES info is in + * auxv, init_pagesizes will use that. However, normally this loop + * does not copy 'pointered' elements (because that would generate + * 'Invalid reads' in the guest). This means that the auxv that + * Valgrind provides to ldrt *doesn't* normally contain + * PAGESIZES. + * + * So init_pagesizes falls back to using sysctlnametomib/sysctl + * to read "hw.pagesizes". Unfortunately there seems to be a bug + * in this for an x86 executable compiled and running on an amd64 + * kernel. + * + * The application sees MAXPAGESLEN as 3 (from the amd64 headers) + * but the x86 kernel sees MAXPAGESLEN as 2. The routine that + * copies out the data for a sysctl sees this discrepancy and + * sets an ENOMEM error. So guest execution doesn't even get past + * executing the dynamic linker. + */ + + for (; orig_auxv->a_type != AT_NULL; auxv++, orig_auxv++) { + + /* copy the entry... */ + *auxv = *orig_auxv; + + /* + * ...and fix up / examine the copy + * in general there are thee possibilities for these items + * 1. copy it, a common case for scalars + * 2. synthesize, if the value that the host gets isn't what we want + * 3. ignore, usually the case for pointers to memory for the host + * the ignored items are just left commented out + */ + switch(auxv->a_type) { + + case AT_IGNORE: + case AT_PHENT: + case AT_PAGESZ: + case AT_FLAGS: + case AT_NOTELF: + case AT_UID: + case AT_EUID: + case AT_GID: + case AT_EGID: + case AT_STACKPROT: + case AT_NCPUS: + case AT_OSRELDATE: +#if (FREEBSD_VERS >= FREEBSD_11) + // FreeBSD 11+ also have HWCAP and HWCAP2 + case AT_EHDRFLAGS: +#endif + /* All these are pointerless, so we don't need to do + anything about them. */ + break; + // case AT_CANARYLEN: + // case AT_EXECPATH: + // case AT_CANARY: +#if defined(VGP_x86_freebsd) + case AT_PAGESIZESLEN: + if (!VG_(is32on64)()) { + VG_(debugLog)(2, "initimg", + "stomping auxv entry %llu\n", + (ULong)auxv->a_type); + auxv->a_type = AT_IGNORE; + } + break; + case AT_PAGESIZES: + if (VG_(is32on64)()) { + pagesizes = VG_(malloc)("initimg-freebsd.cpauxv.1", 2*sizeof(int)); + pagesizes[0] = ((int*)auxv->u.a_ptr)[0]; + pagesizes[1] = ((int*)auxv->u.a_ptr)[1]; + } else { + VG_(debugLog)(2, "initimg", + "stomping auxv entry %llu\n", + (ULong)auxv->a_type); + auxv->a_type = AT_IGNORE; + } + break; +#endif + // case AT_TIMEKEEP: + break; + +#if (FREEBSD_VERS >= FREEBSD_13) + case AT_BSDFLAGS: + case AT_ARGC: + // case AT_ARGV: + case AT_ENVC: + // case AT_ENVV: + // case AT_PS_STRINGS: +#endif + +#if (FREEBSD_VERS >= FREEBSD_14) + // case AT_FXRNG: +#endif + + case AT_PHDR: + if (info->phdr == 0) + auxv->a_type = AT_IGNORE; + else + auxv->u.a_val = info->phdr; + break; + + case AT_PHNUM: + if (info->phdr == 0) + auxv->a_type = AT_IGNORE; + else + auxv->u.a_val = info->phnum; + break; + + case AT_BASE: + auxv->u.a_val = info->interp_offset; + break; + + case AT_ENTRY: + auxv->u.a_val = info->entry; + break; + + default: + /* stomp out anything we don't know about */ + VG_(debugLog)(2, "initimg", + "stomping auxv entry %llu\n", + (ULong)auxv->a_type); + auxv->a_type = AT_IGNORE; + break; + } + } + *auxv = *orig_auxv; + vg_assert(auxv->a_type == AT_NULL); + + vg_assert((strtab-stringbase) == stringsize); + + /* client_SP is pointing at client's argc/argv */ + + if (0) VG_(printf)("startup SP = %#lx\n", client_SP); + return client_SP; +} + + +/* Allocate the client data segment. It is an expandable anonymous + mapping abutting a shrinkable reservation of size max_dseg_size. + The data segment starts at VG_(brk_base), which is page-aligned, + and runs up to VG_(brk_limit), which isn't. */ + +static void setup_client_dataseg ( SizeT max_size ) +{ + Bool ok; + SysRes sres; + Addr anon_start = VG_(brk_base); + SizeT anon_size = VKI_PAGE_SIZE; + Addr resvn_start = anon_start + anon_size; + SizeT resvn_size = max_size - anon_size; + + vg_assert(VG_IS_PAGE_ALIGNED(anon_size)); + vg_assert(VG_IS_PAGE_ALIGNED(resvn_size)); + vg_assert(VG_IS_PAGE_ALIGNED(anon_start)); + vg_assert(VG_IS_PAGE_ALIGNED(resvn_start)); + + /* Because there's been no brk activity yet: */ + vg_assert(VG_(brk_base) == VG_(brk_limit)); + + /* Try to create the data seg and associated reservation where + VG_(brk_base) says. */ + ok = VG_(am_create_reservation)( + resvn_start, + resvn_size, + SmLower, + anon_size + ); + + if (!ok) { + /* Hmm, that didn't work. Well, let aspacem suggest an address + it likes better, and try again with that. */ + anon_start = VG_(am_get_advisory_client_simple) + ( 0/*floating*/, anon_size+resvn_size, &ok ); + if (ok) { + resvn_start = anon_start + anon_size; + ok = VG_(am_create_reservation)( + resvn_start, + resvn_size, + SmLower, + anon_size + ); + if (ok) + VG_(brk_base) = VG_(brk_limit) = anon_start; + } + /* that too might have failed, but if it has, we're hosed: there + is no Plan C. */ + } + vg_assert(ok); + + sres = VG_(am_mmap_anon_fixed_client)( + anon_start, + anon_size, + VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC + ); + vg_assert(!sr_isError(sres)); + vg_assert(sr_Res(sres) == anon_start); +} + + +/*====================================================================*/ +/*=== TOP-LEVEL: VG_(setup_client_initial_image) ===*/ +/*====================================================================*/ + +/* Create the client's initial memory image. */ +IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii, + const VexArchInfo* vex_archinfo ) +{ + ExeInfo info; + HChar** env = NULL; + + IIFinaliseImageInfo iifii = { + .clstack_max_size = 0, + .initial_client_SP = 0, + .initial_client_IP = 0, + .initial_client_TOC = 0, + .client_auxv = NULL, + .arch_elf_state = VKI_INIT_ARCH_ELF_STATE, + }; + + //-------------------------------------------------------------- + // Load client executable, finding in $PATH if necessary + // p: get_helprequest_and_toolname() [for 'exec', 'need_help'] + // p: layout_remaining_space [so there's space] + //-------------------------------------------------------------- + VG_(debugLog)(1, "initimg", "Loading client\n"); + + if (VG_(args_the_exename) == NULL) + VG_(err_missing_prog)(); + + VG_(memset)(&info, 0, sizeof(info)); + + load_client(&info, &iifii.initial_client_IP, &iifii.initial_client_TOC); + + //-------------------------------------------------------------- + // Set up client's environment + // p: set-libdir [for VG_(libdir)] + // p: get_helprequest_and_toolname [for toolname] + //-------------------------------------------------------------- + VG_(debugLog)(1, "initimg", "Setup client env\n"); + env = setup_client_env(iicii.envp, iicii.toolname); + + //-------------------------------------------------------------- + // Setup client stack, eip, and VG_(client_arg[cv]) + // p: load_client() [for 'info'] + // p: fix_environment() [for 'env'] + //-------------------------------------------------------------- + { + /* When allocating space for the client stack, take + notice of the --main-stacksize value. This makes it possible + to run programs with very large (primary) stack requirements + simply by specifying --main-stacksize. */ + /* Logic is as follows: + - by default, use the client's current stack rlimit + - if that exceeds 16M, clamp to 16M + - if a larger --main-stacksize value is specified, use that instead + - in all situations, the minimum allowed stack size is 1M + */ + void* init_sp = iicii.argv - 1; + SizeT m1 = 1024 * 1024; + SizeT m16 = 16 * m1; + SizeT szB = (SizeT)VG_(client_rlimit_stack).rlim_cur; + if (szB < m1) szB = m1; + if (szB > m16) szB = m16; + if (VG_(clo_main_stacksize) > 0) szB = VG_(clo_main_stacksize); + if (szB < m1) szB = m1; + szB = VG_PGROUNDUP(szB); + VG_(debugLog)(1, "initimg", + "Setup client stack: size will be %lu\n", szB); + + iifii.clstack_max_size = szB; + + iifii.initial_client_SP + = setup_client_stack( init_sp, env, + &info, &iifii.client_auxv, + iicii.clstack_end, iifii.clstack_max_size ); + + VG_(free)(env); + + VG_(debugLog)(2, "initimg", + "Client info: " + "initial_IP=%p initial_TOC=%p brk_base=%p\n", + (void*)(iifii.initial_client_IP), + (void*)(iifii.initial_client_TOC), + (void*)VG_(brk_base) ); + VG_(debugLog)(2, "initimg", + "Client info: " + "initial_SP=%p max_stack_size=%lu\n", + (void*)(iifii.initial_client_SP), + (SizeT)iifii.clstack_max_size ); + } + + //-------------------------------------------------------------- + // Setup client data (brk) segment. Initially a 1-page segment + // which abuts a shrinkable reservation. + // p: load_client() [for 'info' and hence VG_(brk_base)] + //-------------------------------------------------------------- + { + SizeT m1 = 1024 * 1024; + SizeT m8 = 8 * m1; + SizeT dseg_max_size = (SizeT)VG_(client_rlimit_data).rlim_cur; + VG_(debugLog)(1, "initimg", "Setup client data (brk) segment\n"); + if (dseg_max_size < m1) dseg_max_size = m1; + if (dseg_max_size > m8) dseg_max_size = m8; + dseg_max_size = VG_PGROUNDUP(dseg_max_size); + + setup_client_dataseg( dseg_max_size ); + } + + VG_(free)(info.interp_name); + info.interp_name = NULL; + VG_(free)(info.interp_args); + info.interp_args = NULL; + return iifii; +} + + +/*====================================================================*/ +/*=== TOP-LEVEL: VG_(finalise_thread1state) ===*/ +/*====================================================================*/ + +/* Just before starting the client, we may need to make final + adjustments to its initial image. Also we need to set up the VEX + guest state for thread 1 (the root thread) and copy in essential + starting values. This is handed the IIFinaliseImageInfo created by + VG_(ii_create_image). +*/ +void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii ) +{ + ThreadArchState* arch = &VG_(threads)[1].arch; + + /* We get client_{ip/sp/toc}, and start the client with + all other registers zeroed. */ + +# if defined(VGP_x86_freebsd) + vg_assert(0 == sizeof(VexGuestX86State) % 16); + + /* Zero out the initial state, and set up the simulated FPU in a + sane way. */ + LibVEX_GuestX86_initialise(&arch->vex); + + /* Zero out the shadow areas. */ + VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestX86State)); + VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestX86State)); + + /* Put essential stuff into the new state. */ + arch->vex.guest_ESP = iifii.initial_client_SP; + arch->vex.guest_EIP = iifii.initial_client_IP; + + /* initialise %cs, %ds and %ss to point at the operating systems + default code, data and stack segments */ + asm volatile("movw %%cs, %0" : : "m" (arch->vex.guest_CS)); + asm volatile("movw %%ds, %0" : : "m" (arch->vex.guest_DS)); + asm volatile("movw %%ss, %0" : : "m" (arch->vex.guest_SS)); + +# elif defined(VGP_amd64_freebsd) + vg_assert(0 == sizeof(VexGuestAMD64State) % 16); + + /* Zero out the initial state, and set up the simulated FPU in a + sane way. */ + LibVEX_GuestAMD64_initialise(&arch->vex); + + /* Zero out the shadow areas. */ + VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestAMD64State)); + VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestAMD64State)); + + /* Put essential stuff into the new state. */ + arch->vex.guest_RSP = ((iifii.initial_client_SP - 8) & ~0xFul) + 8; + arch->vex.guest_RDI = iifii.initial_client_SP; + arch->vex.guest_RIP = iifii.initial_client_IP; + +# else +# error Unknown platform +# endif + + /* Tell the tool that we just wrote to the registers. */ + VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0, + sizeof(VexGuestArchState)); +} + +#endif // defined(VGO_freebsd) + +/*--------------------------------------------------------------------*/ +/*--- ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_sigframe/sigframe-amd64-freebsd.c b/coregrind/m_sigframe/sigframe-amd64-freebsd.c new file mode 100644 index 0000000000..997cf77c7e --- /dev/null +++ b/coregrind/m_sigframe/sigframe-amd64-freebsd.c @@ -0,0 +1,432 @@ + +/*--------------------------------------------------------------------*/ +/*--- Create/destroy signal delivery frames. ---*/ +/*--- sigframe-amd64-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Nicholas Nethercote + njn@valgrind.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_amd64_freebsd) + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_threadstate.h" +#include "pub_core_aspacemgr.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcprint.h" +#include "pub_core_machine.h" +#include "pub_core_options.h" +#include "pub_core_signals.h" +#include "pub_core_tooliface.h" +#include "pub_core_trampoline.h" +#include "pub_core_sigframe.h" /* self */ + +/* This module creates and removes signal frames for signal deliveries + on amd64-freebsd. +*/ + + +/*------------------------------------------------------------*/ +/*--- Signal frame layouts ---*/ +/*------------------------------------------------------------*/ + +// A structure in which to save the application's registers +// during the execution of signal handlers. + +// In theory, so long as we get the arguments to the handler function +// right, it doesn't matter what the exact layout of the rest of the +// frame is. Unfortunately, things like gcc's exception unwinding +// make assumptions about the locations of various parts of the frame, +// so we need to duplicate it exactly. + +/* Valgrind-specific parts of the signal frame */ +struct vg_sigframe { + /* Sanity check word. */ + UInt magicPI; + + UInt handlerflags; /* flags for signal handler */ + + + /* Safely-saved version of sigNo, as described above. */ + Int sigNo_private; + + /* XXX This is wrong. Surely we should store the shadow values + into the shadow memory behind the actual values? */ + VexGuestAMD64State vex_shadow1; + VexGuestAMD64State vex_shadow2; + + /* HACK ALERT */ + VexGuestAMD64State vex; + /* end HACK ALERT */ + + /* saved signal mask to be restored when handler returns */ + vki_sigset_t mask; + + /* Sanity check word. Is the highest-addressed word; do not + move!*/ + UInt magicE; +}; + +struct sigframe { + /* Sig handler's return address */ + Addr retaddr; + + Addr phandler; /* "action" or "handler" */ + + /* pointed to by puContext */ + struct vki_ucontext uContext; + + vki_siginfo_t sigInfo; + + struct _vki_fpstate fpstate; + + struct vg_sigframe vg; +}; + +/*------------------------------------------------------------*/ +/*--- Creating signal frames ---*/ +/*------------------------------------------------------------*/ + +/* Create a plausible-looking sigcontext from the thread's + Vex guest state. +*/ +static +void synth_ucontext(ThreadId tid, const vki_siginfo_t *si, + UWord trapno, UWord err, const vki_sigset_t *set, + struct vki_ucontext *ucp, struct _vki_fpstate *fpstate) +{ + ThreadState *tst = VG_(get_ThreadState)(tid); + struct vki_mcontext *sc = &ucp->uc_mcontext; + + VG_(memset)(ucp, 0, sizeof(*ucp)); + + ucp->uc_flags = 0; + ucp->uc_link = 0; + ucp->uc_sigmask = *set; + ucp->uc_stack = tst->altstack; + VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate)); + +# define SC2(reg,REG) sc->reg = tst->arch.vex.guest_##REG + SC2(r8,R8); + SC2(r9,R9); + SC2(r10,R10); + SC2(r11,R11); + SC2(r12,R12); + SC2(r13,R13); + SC2(r14,R14); + SC2(r15,R15); + SC2(rdi,RDI); + SC2(rsi,RSI); + SC2(rbp,RBP); + SC2(rbx,RBX); + SC2(rdx,RDX); + SC2(rax,RAX); + SC2(rcx,RCX); + SC2(rsp,RSP); + /* + SC2(cs,CS); + SC2(gs,SS); + XXX + */ + SC2(rip,RIP); + sc->addr = (UWord)si->si_addr; + sc->err = err; + sc->fpformat = VKI_FPFMT_NODEV; + sc->ownedfp = VKI_FPOWNED_NONE; + sc->len = sizeof(*sc); + sc->rflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex); + sc->trapno = trapno; +# undef SC2 +} + + +/* Extend the stack segment downwards if needed so as to ensure the + new signal frames are mapped to something. Return a Bool + indicating whether or not the operation was successful. +*/ +static Bool extend ( ThreadState *tst, Addr addr, SizeT size ) +{ + ThreadId tid = tst->tid; + NSegment const* stackseg = NULL; + + if (VG_(extend_stack)(tid, addr)) { + stackseg = VG_(am_find_nsegment)(addr); + if (0 && stackseg) + VG_(printf)("frame=%#lx seg=%#lx-%#lx\n", + addr, stackseg->start, stackseg->end); + } + + if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) { + VG_(message)( + Vg_UserMsg, + "Can't extend stack to %#lx during signal delivery for thread %u:\n", + addr, tid); + if (stackseg == NULL) + VG_(message)(Vg_UserMsg, " no stack segment\n"); + else + VG_(message)(Vg_UserMsg, " too small or bad protection modes\n"); + + /* set SIGSEGV to default handler */ + VG_(set_default_handler)(VKI_SIGSEGV); + VG_(synth_fault_mapping)(tid, addr); + + /* The whole process should be about to die, since the default + action of SIGSEGV to kill the whole process. */ + return False; + } + + /* For tracking memory events, indicate the entire frame has been + allocated. */ + VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB, + size + VG_STACK_REDZONE_SZB, tid ); + + return True; +} + + +/* Build the Valgrind-specific part of a signal frame. */ + +static void build_vg_sigframe(struct vg_sigframe *frame, + ThreadState *tst, + const vki_sigset_t *mask, + UInt flags, + Int sigNo) +{ + frame->sigNo_private = sigNo; + frame->magicPI = 0x31415927; + frame->vex_shadow1 = tst->arch.vex_shadow1; + frame->vex_shadow2 = tst->arch.vex_shadow2; + /* HACK ALERT */ + frame->vex = tst->arch.vex; + /* end HACK ALERT */ + frame->mask = tst->sig_mask; + frame->handlerflags = flags; + frame->magicE = 0x27182818; +} + +static Addr build_sigframe(ThreadState *tst, + Addr rsp_top_of_frame, + const vki_siginfo_t *siginfo, + const struct vki_ucontext *siguc, + void *handler, UInt flags, + const vki_sigset_t *mask, + void *restorer) +{ + struct sigframe *frame; + Addr rsp = rsp_top_of_frame; + Int sigNo = siginfo->si_signo; + UWord trapno; + UWord err; + + rsp -= sizeof(*frame); + rsp = VG_ROUNDDN(rsp, 16) - 8; + frame = (struct sigframe *)rsp; + + if (!extend(tst, rsp, sizeof(*frame))) + return rsp_top_of_frame; + + /* retaddr, siginfo, uContext fields are to be written */ + VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame", + rsp, offsetof(struct sigframe, vg) ); + + frame->retaddr = (Addr)&VG_(amd64_freebsd_SUBST_FOR_sigreturn); + + if (siguc) { + trapno = siguc->uc_mcontext.trapno; + err = siguc->uc_mcontext.err; + } else { + trapno = 0; + err = 0; + } + + VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t)); + + if (sigNo == VKI_SIGILL && siginfo->si_code > 0) + frame->sigInfo.si_addr = (void*)tst->arch.vex.guest_RIP; + + synth_ucontext(tst->tid, siginfo, trapno, err, mask, + &frame->uContext, &frame->fpstate); + + VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, + rsp, offsetof(struct sigframe, vg) ); + + build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo); + + return rsp; +} + + +void VG_(sigframe_create)( ThreadId tid, + Bool on_altstack, + Addr rsp_top_of_frame, + const vki_siginfo_t *siginfo, + const struct vki_ucontext *siguc, + void *handler, + UInt flags, + const vki_sigset_t *mask, + void *restorer ) +{ + Addr rsp; + struct sigframe *frame; + ThreadState* tst = VG_(get_ThreadState)(tid); + + rsp = build_sigframe(tst, rsp_top_of_frame, siginfo, siguc, handler, + flags, mask, restorer); + frame = (struct sigframe *)rsp; + + /* Set the thread so it will next run the handler. */ + /* tst->m_rsp = rsp; also notify the tool we've updated RSP */ + VG_(set_SP)(tid, rsp); + VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(Addr)); + + //VG_(printf)("handler = %p\n", handler); + tst->arch.vex.guest_RIP = (Addr) handler; + tst->arch.vex.guest_RDI = (ULong) siginfo->si_signo; + tst->arch.vex.guest_RSI = (Addr) &frame->sigInfo; + tst->arch.vex.guest_RDX = (Addr) &frame->uContext; + /* And tell the tool that these registers have been written. */ + VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, + offsetof(VexGuestAMD64State,guest_RIP), sizeof(UWord) ); + VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, + offsetof(VexGuestAMD64State,guest_RDI), sizeof(UWord) ); + VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, + offsetof(VexGuestAMD64State,guest_RSI), sizeof(UWord) ); + VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid, + offsetof(VexGuestAMD64State,guest_RDX), sizeof(UWord) ); + + /* This thread needs to be marked runnable, but we leave that the + caller to do. */ +} + + +/*------------------------------------------------------------*/ +/*--- Destroying signal frames ---*/ +/*------------------------------------------------------------*/ + +/* Return False and don't do anything, just set the client to take a + segfault, if it looks like the frame is corrupted. */ +static +Bool restore_vg_sigframe ( ThreadState *tst, + struct vg_sigframe *frame, Int *sigNo ) +{ + if (frame->magicPI != 0x31415927 || + frame->magicE != 0x27182818) { + VG_(message)(Vg_UserMsg, "Thread %u return signal frame " + "corrupted. Killing process.\n", + tst->tid); + VG_(set_default_handler)(VKI_SIGSEGV); + VG_(synth_fault)(tst->tid); + *sigNo = VKI_SIGSEGV; + return False; + } + tst->sig_mask = frame->mask; + tst->tmp_sig_mask = frame->mask; + tst->arch.vex_shadow1 = frame->vex_shadow1; + tst->arch.vex_shadow2 = frame->vex_shadow2; + /* HACK ALERT */ + tst->arch.vex = frame->vex; + /* end HACK ALERT */ + *sigNo = frame->sigNo_private; + return True; +} + +static +void restore_sigcontext( ThreadState *tst, + struct vki_mcontext *sc, + struct _vki_fpstate *fpstate ) +{ + tst->arch.vex.guest_RAX = sc->rax; + tst->arch.vex.guest_RCX = sc->rcx; + tst->arch.vex.guest_RDX = sc->rdx; + tst->arch.vex.guest_RBX = sc->rbx; + tst->arch.vex.guest_RBP = sc->rbp; + tst->arch.vex.guest_RSP = sc->rsp; + tst->arch.vex.guest_RSI = sc->rsi; + tst->arch.vex.guest_RDI = sc->rdi; + tst->arch.vex.guest_R8 = sc->r8; + tst->arch.vex.guest_R9 = sc->r9; + tst->arch.vex.guest_R10 = sc->r10; + tst->arch.vex.guest_R11 = sc->r11; + tst->arch.vex.guest_R12 = sc->r12; + tst->arch.vex.guest_R13 = sc->r13; + tst->arch.vex.guest_R14 = sc->r14; + tst->arch.vex.guest_R15 = sc->r15; + /* + XXX: + tst->arch.vex.guest_rflags = sc->rflags; + */ + tst->arch.vex.guest_RIP = sc->rip; + /* + XXX + tst->arch.vex.guest_CS = sc->cs; + tst->arch.vex.guest_SS = sc->ss; + */ + VG_(memcpy)(fpstate, &sc->fpstate, sizeof(*fpstate)); +} + +static +SizeT restore_sigframe ( ThreadState *tst, + struct sigframe *frame, Int *sigNo ) +{ + if (restore_vg_sigframe(tst, &frame->vg, sigNo)) + restore_sigcontext(tst, &frame->uContext.uc_mcontext, &frame->fpstate); + + return sizeof(*frame); +} + +void VG_(sigframe_destroy)( ThreadId tid ) +{ + Addr rsp; + ThreadState* tst; + SizeT size; + Int sigNo; + + tst = VG_(get_ThreadState)(tid); + + /* Correctly reestablish the frame base address. */ + rsp = tst->arch.vex.guest_RSP; + + size = restore_sigframe(tst, (struct sigframe *)rsp, &sigNo); + + VG_TRACK( die_mem_stack_signal, rsp - VG_STACK_REDZONE_SZB, + size + VG_STACK_REDZONE_SZB ); + + if (VG_(clo_trace_signals)) + VG_(message)( + Vg_DebugMsg, + "VG_(signal_return) (thread %u): valid magic; RIP=%#llx\n", + tid, tst->arch.vex.guest_RIP); + + /* tell the tools */ + VG_TRACK( post_deliver_signal, tid, sigNo ); +} + +#endif // defined(VGP_amd64_freebsd) + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_sigframe/sigframe-x86-freebsd.c b/coregrind/m_sigframe/sigframe-x86-freebsd.c new file mode 100644 index 0000000000..a1d8638e5a --- /dev/null +++ b/coregrind/m_sigframe/sigframe-x86-freebsd.c @@ -0,0 +1,457 @@ + +/*--------------------------------------------------------------------*/ +/*--- Create/destroy signal delivery frames. ---*/ +/*--- sigframe-x86-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Nicholas Nethercote + njn@valgrind.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_x86_freebsd) + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy +#include "pub_core_threadstate.h" +#include "pub_core_aspacemgr.h" /* find_segment */ +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcprint.h" +#include "pub_core_machine.h" +#include "pub_core_options.h" +#include "pub_core_signals.h" +#include "pub_core_tooliface.h" +#include "pub_core_trampoline.h" +#include "pub_core_sigframe.h" /* self */ + + +/* This module creates and removes signal frames for signal deliveries + on x86-freebsd. +*/ + + +/*------------------------------------------------------------*/ +/*--- Signal frame layouts ---*/ +/*------------------------------------------------------------*/ + +// A structure in which to save the application's registers +// during the execution of signal handlers. + +// In theory, so long as we get the arguments to the handler function +// right, it doesn't matter what the exact layout of the rest of the +// frame is. Unfortunately, things like gcc's exception unwinding +// make assumptions about the locations of various parts of the frame, +// so we need to duplicate it exactly. + +/* Valgrind-specific parts of the signal frame */ +struct vg_sigframe { + /* Sanity check word. */ + UInt magicPI; + + UInt handlerflags; /* flags for signal handler */ + + + /* Safely-saved version of sigNo, as described above. */ + Int sigNo_private; + + /* XXX This is wrong. Surely we should store the shadow values + into the shadow memory behind the actual values? */ + VexGuestX86State vex_shadow1; + VexGuestX86State vex_shadow2; + + /* HACK ALERT */ + VexGuestX86State vex; + /* end HACK ALERT */ + + /* saved signal mask to be restored when handler returns */ + vki_sigset_t mask; + + /* Sanity check word. Is the highest-addressed word; do not + move!*/ + UInt magicE; +}; + +struct sigframe { + /* Sig handler's return address */ + Addr retaddr; + + /* + * The following 7 members are roughly the same as + * 'stuct sigframe' in x86/sigrame.h + */ + Int sigNo; + Addr psigInfo; /* code or pointer to sigContext */ + Addr puContext; /* points to uContext */ + Addr addr; /* "secret" 4th argument */ + Addr phandler; /* "action" or "handler" */ + + /* pointed to by puContext */ + struct vki_ucontext uContext; + + vki_siginfo_t sigInfo; + + struct _vki_fpstate fpstate; + + struct vg_sigframe vg; +}; + + +/*------------------------------------------------------------*/ +/*--- Creating signal frames ---*/ +/*------------------------------------------------------------*/ + +/* Create a plausible-looking sigcontext from the thread's + Vex guest state. +*/ +static +void synth_ucontext(ThreadId tid, const vki_siginfo_t *si, + UWord trapno, UWord err, const vki_sigset_t *set, + struct vki_ucontext *uc, struct _vki_fpstate *fpstate) +{ + ThreadState *tst = VG_(get_ThreadState)(tid); + struct vki_mcontext *sc = &uc->uc_mcontext; + + VG_(memset)(uc, 0, sizeof(*uc)); + + uc->uc_flags = 0; + uc->uc_link = 0; + uc->uc_sigmask = *set; + uc->uc_stack = tst->altstack; + VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate)); + +# define SC2(reg,REG) sc->reg = tst->arch.vex.guest_##REG + SC2(gs,GS); + SC2(fs,FS); + SC2(es,ES); + SC2(ds,DS); + + SC2(edi,EDI); + SC2(esi,ESI); + SC2(ebp,EBP); + SC2(esp,ESP); + SC2(ebx,EBX); + SC2(edx,EDX); + SC2(ecx,ECX); + SC2(eax,EAX); + + SC2(eip,EIP); + SC2(cs,CS); + sc->eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex); + SC2(ss,SS); + sc->trapno = trapno; + sc->err = err; +// sc->addr = (UWord)si->si_addr; + sc->fpformat = VKI_FPFMT_NODEV; + sc->len = sizeof(*sc); + sc->ownedfp = VKI_FPOWNED_NONE; +# undef SC2 + +// sc->cr2 = (UInt)si->_sifields._sigfault._addr; +} + + +/* Extend the stack segment downwards if needed so as to ensure the + new signal frames are mapped to something. Return a Bool + indicating whether or not the operation was successful. +*/ +static Bool extend ( ThreadState *tst, Addr addr, SizeT size ) +{ + ThreadId tid = tst->tid; + NSegment const* stackseg = NULL; + + if (VG_(extend_stack)(tid, addr)) { + stackseg = VG_(am_find_nsegment)(addr); + if (0 && stackseg) + VG_(printf)("frame=%#lx seg=%#lx-%#lx\n", + addr, stackseg->start, stackseg->end); + } + + if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) { + VG_(message)( + Vg_UserMsg, + "Can't extend stack to %#lx during signal delivery for thread %u:\n", + addr, tid); + if (stackseg == NULL) + VG_(message)(Vg_UserMsg, " no stack segment\n"); + else + VG_(message)(Vg_UserMsg, " too small or bad protection modes\n"); + + /* set SIGSEGV to default handler */ + VG_(set_default_handler)(VKI_SIGSEGV); + VG_(synth_fault_mapping)(tid, addr); + + /* The whole process should be about to die, since the default + action of SIGSEGV to kill the whole process. */ + return False; + } + + /* For tracking memory events, indicate the entire frame has been + allocated. */ + VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB, + size + VG_STACK_REDZONE_SZB, tid ); + + return True; +} + + +/* Build the Valgrind-specific part of a signal frame. */ + +static void build_vg_sigframe(struct vg_sigframe *frame, + ThreadState *tst, + const vki_sigset_t *mask, + UInt flags, + Int sigNo) +{ + frame->sigNo_private = sigNo; + frame->magicPI = 0x31415927; + frame->vex_shadow1 = tst->arch.vex_shadow1; + frame->vex_shadow2 = tst->arch.vex_shadow2; + /* HACK ALERT */ + frame->vex = tst->arch.vex; + /* end HACK ALERT */ + frame->mask = tst->sig_mask; + frame->handlerflags = flags; + frame->magicE = 0x27182818; +} + +/* + * According to the comments in lib/libc/i386/gen/signalcontext.c + * the stack sould look like this [where n = 4 = sizeof(int)] + * + * 2n+sizeof(struct sigframe) ucp + * 2n struct sigframe + * 1n &func + * 0n &_ctx_start + * + * Note that the 'struct sigframe' above is the one defined in FreeBSD. + * 5 word members + ucontext + siginfo + * + * 'struct sigframe' below is the one defined in this file: + * + * Addr + * FreeBSD struct sigfame + * fpstate + * vg_sigframe + * + */ +static Addr build_sigframe(ThreadState *tst, + Addr esp_top_of_frame, + const vki_siginfo_t *siginfo, + const struct vki_ucontext *siguc, + void *handler, UInt flags, + const vki_sigset_t *mask, + void *restorer) +{ + struct sigframe *frame; + Addr esp = esp_top_of_frame; + Int sigNo = siginfo->si_signo; + UWord trapno; + UWord err; + +#if defined(__clang__) + esp -= 4; + esp = VG_ROUNDDN(esp, 16); + esp -= sizeof(*frame) + 4; +#else + esp -= sizeof(*frame); + esp = VG_ROUNDDN(esp, 16); +#endif + + frame = (struct sigframe *)esp; + + if (!extend(tst, esp, sizeof(*frame))) + return esp_top_of_frame; + + /* retaddr, siginfo, uContext fields are to be written */ + VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame", + esp, offsetof(struct sigframe, vg) ); + + frame->sigNo = sigNo; + frame->retaddr = (Addr)&VG_(x86_freebsd_SUBST_FOR_sigreturn); + if ((flags & VKI_SA_SIGINFO) == 0) + frame->psigInfo = (Addr)siginfo->si_code; + else + frame->psigInfo = (Addr)&frame->sigInfo; + VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t)); + + if (siguc != NULL) { + trapno = siguc->uc_mcontext.trapno; + err = siguc->uc_mcontext.err; + } else { + trapno = 0; + err = 0; + } + + synth_ucontext(tst->tid, siginfo, trapno, err, mask, + &frame->uContext, &frame->fpstate); + + if (sigNo == VKI_SIGILL && siginfo->si_code > 0) + frame->sigInfo.si_addr = (void*)tst->arch.vex.guest_EIP; + + VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, + esp, offsetof(struct sigframe, vg) ); + + build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo); + + return esp; +} + +/* EXPORTED */ +void VG_(sigframe_create)( ThreadId tid, + Bool on_altstack, + Addr esp_top_of_frame, + const vki_siginfo_t *siginfo, + const struct vki_ucontext *siguc, + void *handler, + UInt flags, + const vki_sigset_t *mask, + void *restorer ) +{ + Addr esp; + struct sigframe *frame; + ThreadState* tst = VG_(get_ThreadState)(tid); + + esp = build_sigframe(tst, esp_top_of_frame, siginfo, siguc, handler, + flags, mask, restorer); + frame = (struct sigframe *)esp; + + /* Set the thread so it will next run the handler. */ + /* tst->m_esp = esp; also notify the tool we've updated ESP */ + VG_(set_SP)(tid, esp); + VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(Addr)); + + tst->arch.vex.guest_EIP = (Addr) handler; + tst->arch.vex.guest_EDI = (ULong) siginfo->si_signo; + tst->arch.vex.guest_ESI = (Addr) &frame->sigInfo; + tst->arch.vex.guest_EDX = (Addr) &frame->uContext; + /* This thread needs to be marked runnable, but we leave that the + caller to do. */ + + if (0) + VG_(printf)("pushed signal frame; %%ESP now = %#lx, " + "next %%EIP = %#x, status=%u\n", + esp, tst->arch.vex.guest_EIP, tst->status); +} + + +/*------------------------------------------------------------*/ +/*--- Destroying signal frames ---*/ +/*------------------------------------------------------------*/ + +/* Return False and don't do anything, just set the client to take a + segfault, if it looks like the frame is corrupted. */ +static +Bool restore_vg_sigframe ( ThreadState *tst, + struct vg_sigframe *frame, Int *sigNo ) +{ + if (frame->magicPI != 0x31415927 || + frame->magicE != 0x27182818) { + VG_(message)(Vg_UserMsg, "Thread %u return signal frame " + "corrupted. Killing process.", tst->tid); + VG_(set_default_handler)(VKI_SIGSEGV); + VG_(synth_fault)(tst->tid); + *sigNo = VKI_SIGSEGV; + return False; + } + tst->sig_mask = frame->mask; + tst->tmp_sig_mask = frame->mask; + tst->arch.vex_shadow1 = frame->vex_shadow1; + tst->arch.vex_shadow2 = frame->vex_shadow2; + /* HACK ALERT */ + tst->arch.vex = frame->vex; + /* end HACK ALERT */ + *sigNo = frame->sigNo_private; + return True; +} + +static +void restore_sigcontext( ThreadState *tst, + struct vki_mcontext *sc, + struct _vki_fpstate *fpstate ) +{ + tst->arch.vex.guest_EAX = sc->eax; + tst->arch.vex.guest_ECX = sc->ecx; + tst->arch.vex.guest_EDX = sc->edx; + tst->arch.vex.guest_EBX = sc->ebx; + tst->arch.vex.guest_EBP = sc->ebp; + tst->arch.vex.guest_ESP = sc->esp; + tst->arch.vex.guest_ESI = sc->esi; + tst->arch.vex.guest_EDI = sc->edi; +//:: tst->arch.vex.guest_eflags = sc->eflags; + tst->arch.vex.guest_EIP = sc->eip; + tst->arch.vex.guest_CS = sc->cs; + tst->arch.vex.guest_SS = sc->ss; + tst->arch.vex.guest_DS = sc->ds; + tst->arch.vex.guest_ES = sc->es; + tst->arch.vex.guest_FS = sc->fs; + tst->arch.vex.guest_GS = sc->gs; + VG_(memcpy)(fpstate, &sc->fpstate, sizeof(*fpstate)); +} + + +static +SizeT restore_sigframe ( ThreadState *tst, + struct sigframe *frame, Int *sigNo ) +{ + if (restore_vg_sigframe(tst, &frame->vg, sigNo)) + restore_sigcontext(tst, &frame->uContext.uc_mcontext, &frame->fpstate); + + return sizeof(*frame); +} + +/* EXPORTED */ +void VG_(sigframe_destroy)( ThreadId tid ) +{ + Addr esp; + ThreadState* tst; + SizeT size; + Int sigNo; + + tst = VG_(get_ThreadState)(tid); + + /* Correctly reestablish the frame base address. */ + esp = tst->arch.vex.guest_ESP; + esp += 8; /* Clean up stack from argument/ret passed to sigreturn(2) */ + + size = restore_sigframe(tst, (struct sigframe *)esp, &sigNo); + + VG_TRACK( die_mem_stack_signal, esp - VG_STACK_REDZONE_SZB, + size + VG_STACK_REDZONE_SZB ); + + if (VG_(clo_trace_signals)) + VG_(message)( + Vg_DebugMsg, + "VG_(signal_return) (thread %u): EIP=%#x\n", + tid, tst->arch.vex.guest_EIP); + + /* tell the tools */ + VG_TRACK( post_deliver_signal, tid, sigNo ); +} + +#endif // defined(VGP_x86_freebsd) + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/priv_syswrap-freebsd.h b/coregrind/m_syswrap/priv_syswrap-freebsd.h new file mode 100644 index 0000000000..348a7fcdbd --- /dev/null +++ b/coregrind/m_syswrap/priv_syswrap-freebsd.h @@ -0,0 +1,554 @@ + +/*--------------------------------------------------------------------*/ +/*--- FreeBSD-specific syscalls stuff. priv_syswrap-freebsd.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2008 Nicholas Nethercote + njn@valgrind.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef PRIV_SYSWRAP_FREEBSD_H +#define PRIV_SYSWRAP_FREEBSD_H + +/* requires #include "priv_types_n_macros.h" */ +#include "priv_types_n_macros.h" +#include "config.h" + +// Clone-related functions +extern Word ML_(start_thread_NORETURN) ( void* arg ); +extern Addr ML_(allocstack) ( ThreadId tid ); +extern void ML_(call_on_new_stack_0_1) ( Addr stack, Addr retaddr, + void (*f)(Word), Word arg1 ); +extern SysRes ML_(do_fork) ( ThreadId tid ); +extern SysRes ML_(do_vfork) ( ThreadId tid ); +extern SysRes ML_(do_rfork) ( ThreadId tid, Int flags ); + + +DECL_TEMPLATE(freebsd, sys_syscall) +DECL_TEMPLATE(freebsd, sys_exit) // 1 +DECL_TEMPLATE(freebsd, sys_fork) // 2 +// generic read 3 +// generic write 4 +// generic open 5 +// generic close 6 +// generic wait4 7 +// generic link 9 +// generic unlink 10 +// generic chdir 12 +// generic fchdir 13 +// generic mknod 14 +// generic chmod 15 +// generic chown 16 +// generic brk 17 +DECL_TEMPLATE(freebsd, sys_mount) // 21 +DECL_TEMPLATE(freebsd, sys_unmount) // 22 +DECL_TEMPLATE(freebsd, sys_ptrace) // 26 +DECL_TEMPLATE(freebsd, sys_recvmsg) // 27 +DECL_TEMPLATE(freebsd, sys_sendmsg) // 28 +DECL_TEMPLATE(freebsd, sys_recvfrom) // 29 +DECL_TEMPLATE(freebsd, sys_accept) // 30 +DECL_TEMPLATE(freebsd, sys_getpeername) // 31 +DECL_TEMPLATE(freebsd, sys_getsockname) // 32 +// generic access 33 +DECL_TEMPLATE(freebsd, sys_chflags) // 34 +DECL_TEMPLATE(freebsd, sys_fchflags) // 35 +// generic sync 36 +// generic kill 37 +// generic getppid 39 +// generic dup 41 +DECL_TEMPLATE(freebsd, sys_pipe) // 42 +// generic getegid 43 +// generic profil redirect to ni_syscall 44 +// sys_ktrace refirect to ni_syscall 45 +// generic getgid 47 +DECL_TEMPLATE(freebsd, sys_getlogin) // 49 +DECL_TEMPLATE(freebsd, sys_setlogin) // 50 +// generic acct 51 +// generic sigaltstack 53 +DECL_TEMPLATE(freebsd, sys_ioctl) // 54 +DECL_TEMPLATE(freebsd, sys_reboot) // 55 +DECL_TEMPLATE(freebsd, sys_revoke) // 56 +// generic symlink 57 +// generic readlink 58 +// generic execve 59 +// generic umask 60 +// generic chroot 61 +// generic msync 65 +DECL_TEMPLATE(freebsd, sys_vfork) // 66 +DECL_TEMPLATE(freebsd, sys_sbrk) // 69 + +// freebsd11 vadvise 72 +// generic munmap 73 +// generic mprotect 74 +// generic madvise 75 +// generic mincore 78 +// generic getgroups 79 +// generic setgroups 80 +// generic getpgrp 81 +// generic setpgid 82 +// generic setitimer 83 + +DECL_TEMPLATE(freebsd, sys_swapon) // 85 +// generic getitimer 86 +DECL_TEMPLATE(freebsd, sys_getdtablesize) // 90 +DECL_TEMPLATE(freebsd, sys_fcntl) // 92 +// generic select 93 +// generic fsync 95 +// generic setpriority 96 +DECL_TEMPLATE(freebsd, sys_socket) // 97 +DECL_TEMPLATE(freebsd, sys_connect) // 98 +// generic getpriority 100 +DECL_TEMPLATE(freebsd, sys_bind) // 104 +DECL_TEMPLATE(freebsd, sys_setsockopt) // 105 +DECL_TEMPLATE(freebsd, sys_listen) // 106 +// generic gettimeofday 116 +// generic rusage 117 +DECL_TEMPLATE(freebsd, sys_getsockopt) // 118 + +// generic readv 120 +// generic writev 121 +// generic settimeofday 122 +// generic fchown 123 +// generic fchmod 124 +// generic setreuid 126 +// generic setregid 127 +// generic rename 128 +// generic flock 131 +DECL_TEMPLATE(freebsd, sys_mkfifo) // 132 +DECL_TEMPLATE(freebsd, sys_sendto) // 133 +DECL_TEMPLATE(freebsd, sys_shutdown) // 134 +DECL_TEMPLATE(freebsd, sys_socketpair) // 135 +// generic mkdir 136 +// generic rmdir 137 +// generic utims 138 +DECL_TEMPLATE(freebsd, sys_adjtime) // 140 +// generic setsid 147 +DECL_TEMPLATE(freebsd, sys_quotactl) // 148 +// unimp nlm_syscall 154 +//DECL_TEMPLATE(freebsd, sys_nfssvc) 155 +DECL_TEMPLATE(freebsd, sys_lgetfh) // 160 +DECL_TEMPLATE(freebsd, sys_getfh) // 161 +#if (FREEBSD_VERS <= FREEBSD_10) +DECL_TEMPLATE(freebsd, sys_freebsd4_getdomainname) // 162 +DECL_TEMPLATE(freebsd, sys_freebsd4_setdomainname) // 163 +DECL_TEMPLATE(freebsd, sys_freebsd4_uname) // 164 +#endif +DECL_TEMPLATE(freebsd, sys_sysarch) // 165 +DECL_TEMPLATE(freebsd, sys_rtprio) // 166 +//DECL_TEMPLATE(freebsd, sys_semsys) 169 +//DECL_TEMPLATE(freebsd, sys_msgsys) 170 +//DECL_TEMPLATE(freebsd, sys_shmsys) 171 +#if (FREEBSD_VERS <= FREEBSD_10) +DECL_TEMPLATE(freebsd, sys_freebsd6_pread) // 173 +DECL_TEMPLATE(freebsd, sys_freebsd6_pwrite) // 174 +#endif +DECL_TEMPLATE(freebsd, sys_setfib) // 175 +//DECL_TEMPLATE(freebsd, sys_ntp_adjtime) 176 +// generic setgid 181 +DECL_TEMPLATE(freebsd, sys_setegid) // 182 +DECL_TEMPLATE(freebsd, sys_seteuid) // 183 +#if (FREEBSD_VERS >= FREEBSD_12) +DECL_TEMPLATE(freebsd, sys_freebsd11_stat) // 188 +DECL_TEMPLATE(freebsd, sys_freebsd11_fstat) // 189 +DECL_TEMPLATE(freebsd, sys_freebsd11_lstat)// 190 +#else +DECL_TEMPLATE(freebsd, sys_stat) // 188 +DECL_TEMPLATE(freebsd, sys_fstat) // 189 +DECL_TEMPLATE(freebsd, sys_lstat) // 190 +#endif +DECL_TEMPLATE(freebsd, sys_pathconf) // 191 +DECL_TEMPLATE(freebsd, sys_fpathconf) // 192 +// generic getrlimit 194 +// generic setrlimit 195 +#if (FREEBSD_VERS >= FREEBSD_12) +DECL_TEMPLATE(freebsd, sys_freebsd11_getdirentries) // 196 +#else +DECL_TEMPLATE(freebsd, sys_getdirentries) // 196 +#endif + +#if (FREEBSD_VERS <= FREEBSD_10) +DECL_TEMPLATE(freebsd, sys_freebsd6_mmap) // 197 +#endif + +#if (FREEBSD_VERS <= FREEBSD_10) +DECL_TEMPLATE(freebsd, sys_freebsd6_lseek) // 199 +DECL_TEMPLATE(freebsd, sys_freebsd6_truncate) // 200 +DECL_TEMPLATE(freebsd, sys_freebsd6_ftruncate) // 201 +#endif +DECL_TEMPLATE(freebsd, sys___sysctl) // 202 +// generic mlock 202 +// generic munlock 203 +DECL_TEMPLATE(freebsd, sys_undelete) // 205 +DECL_TEMPLATE(freebsd, sys_futimes) // 206 +// generic getpgod 207 +// generic poll 209 +DECL_TEMPLATE(freebsd, sys_freebsd7___semctl) // 220 +DECL_TEMPLATE(freebsd, sys_semget) // 221 +DECL_TEMPLATE(freebsd, sys_semop) // 222 +DECL_TEMPLATE(freebsd, sys_freebsd7_msgctl) // 224 +DECL_TEMPLATE(freebsd, sys_msgget) // 225 +DECL_TEMPLATE(freebsd, sys_msgsnd) // 226 +DECL_TEMPLATE(freebsd, sys_msgrcv) // 227 +DECL_TEMPLATE(freebsd, sys_shmat) // 228 +DECL_TEMPLATE(freebsd, sys_freebsd7_shmctl) // 229 +DECL_TEMPLATE(freebsd, sys_shmdt) // 230 +DECL_TEMPLATE(freebsd, sys_shmget) // 231 +DECL_TEMPLATE(freebsd, sys_clock_gettime) // 232 +DECL_TEMPLATE(freebsd, sys_clock_settime) // 233 +DECL_TEMPLATE(freebsd, sys_clock_getres) // 234 +DECL_TEMPLATE(freebsd, sys_timer_create) // 235 +DECL_TEMPLATE(freebsd, sys_timer_delete) // 236 +DECL_TEMPLATE(freebsd, sys_timer_settime) // 237 +DECL_TEMPLATE(freebsd, sys_timer_gettime) // 238 +DECL_TEMPLATE(freebsd, sys_timer_getoverrun) // 239 +// generic sys_nanosleep 240 +// unimpl ffclock_getcounter 241 +// unimpl ffclock_setestimate 242 +// unimpl ffclock_getestimate 243 +DECL_TEMPLATE(freebsd, sys_clock_nanosleep) // 244 +// unimpl clock_getcpuclockid2 247 +// unimpl ntp_gettime 248 +DECL_TEMPLATE(freebsd, sys_minherit) // 250 +DECL_TEMPLATE(freebsd, sys_rfork) // 251 +DECL_TEMPLATE(freebsd, sys_issetugid) // 253 +// generic lchown 254 +DECL_TEMPLATE(freebsd, sys_aio_read) // 255 +DECL_TEMPLATE(freebsd, sys_aio_write) // 256 +DECL_TEMPLATE(freebsd, sys_lio_listio) // 257 +// generic sys_getdents 272 +DECL_TEMPLATE(freebsd, sys_lchmod) // 274 +DECL_TEMPLATE(freebsd, sys_lutimes) // 276 + +// unimpl freebsd11_nstat 278 +// unimpl freebsd11_nfstat 279 +// unimpl freebsd11_nlstat 280 +DECL_TEMPLATE(freebsd, sys_preadv) // 289 +DECL_TEMPLATE(freebsd, sys_pwritev) // 290 + +DECL_TEMPLATE(freebsd, sys_fhopen) // 298 + +#if (FREEBSD_VERS >= FREEBSD_12) +DECL_TEMPLATE(freebsd, sys_freebsd11_fhstat) // 299 +#else +DECL_TEMPLATE(freebsd, sys_fhstat) // 299 +#endif + +DECL_TEMPLATE(freebsd, sys_modnext) // 300 +DECL_TEMPLATE(freebsd, sys_modstat) // 301 +DECL_TEMPLATE(freebsd, sys_modfnext) // 302 +DECL_TEMPLATE(freebsd, sys_modfind) // 303 + +DECL_TEMPLATE(freebsd, sys_kldload) // 304 +DECL_TEMPLATE(freebsd, sys_kldunload) // 305 +DECL_TEMPLATE(freebsd, sys_kldfind) // 306 +DECL_TEMPLATE(freebsd, sys_kldnext) // 307 +DECL_TEMPLATE(freebsd, sys_kldstat) // 308 +DECL_TEMPLATE(freebsd, sys_kldfirstmod) // 309 +DECL_TEMPLATE(freebsd, sys_setresuid) // 311 +DECL_TEMPLATE(freebsd, sys_setresgid) // 312 +DECL_TEMPLATE(freebsd, sys_aio_return) //314 +DECL_TEMPLATE(freebsd, sys_aio_suspend) // 315 +DECL_TEMPLATE(freebsd, sys_aio_cancel) // 316 +DECL_TEMPLATE(freebsd, sys_aio_error) // 317 +DECL_TEMPLATE(freebsd, sys_yield) // 321 +DECL_TEMPLATE(freebsd, sys_munlockall) // 325 +DECL_TEMPLATE(freebsd, sys___getcwd) // 326 +DECL_TEMPLATE(freebsd, sys_sched_setparam) // 327 +DECL_TEMPLATE(freebsd, sys_sched_getparam) // 328 +DECL_TEMPLATE(freebsd, sys_sched_setscheduler) // 329 +DECL_TEMPLATE(freebsd, sys_sched_getscheduler) // 330 +DECL_TEMPLATE(freebsd, sys_sched_yield) // 331 +DECL_TEMPLATE(freebsd, sys_sched_get_priority_max) // 332 +DECL_TEMPLATE(freebsd, sys_sched_get_priority_min) // 333 +DECL_TEMPLATE(freebsd, sys_sched_rr_get_interval) // 334 +DECL_TEMPLATE(freebsd, sys_utrace) // 335 +DECL_TEMPLATE(freebsd, sys_kldsym) // 337 +DECL_TEMPLATE(freebsd, sys_jail) // 338 +// unimpl SYS_nnpfs_syscall 339 +DECL_TEMPLATE(freebsd, sys_sigprocmask) // 340 +DECL_TEMPLATE(freebsd, sys_sigsuspend) // 341 + +DECL_TEMPLATE(freebsd, sys_sigpending) // 343 + +DECL_TEMPLATE(freebsd, sys_sigtimedwait) // 345 +DECL_TEMPLATE(freebsd, sys_sigwaitinfo) // 346 +DECL_TEMPLATE(freebsd, sys___acl_get_file) // 347 +DECL_TEMPLATE(freebsd, sys___acl_set_file) // 348 +DECL_TEMPLATE(freebsd, sys___acl_get_fd) // // 349 +DECL_TEMPLATE(freebsd, sys___acl_set_fd) // 350 +DECL_TEMPLATE(freebsd, sys___acl_delete_file) // 351 +DECL_TEMPLATE(freebsd, sys___acl_delete_fd) // 352 +DECL_TEMPLATE(freebsd, sys___acl_aclcheck_file) // 353 +DECL_TEMPLATE(freebsd, sys___acl_aclcheck_fd) // 354 + +DECL_TEMPLATE(freebsd, sys_extattrctl) // 355 +DECL_TEMPLATE(freebsd, sys_extattr_set_file) // 356 +DECL_TEMPLATE(freebsd, sys_extattr_get_file) // 357 +DECL_TEMPLATE(freebsd, sys_extattr_delete_file) // 358 +DECL_TEMPLATE(freebsd, sys_aio_waitcomplete) // 350 +DECL_TEMPLATE(freebsd, sys_getresuid) // 360 +DECL_TEMPLATE(freebsd, sys_getresgid) // 361 +DECL_TEMPLATE(freebsd, sys_kqueue) // 362 + +#if (FREEBSD_VERS >= FREEBSD_12) +DECL_TEMPLATE(freebsd, sys_freebsd11_kevent) // 363 +#else +DECL_TEMPLATE(freebsd, sys_kevent) // 363 +#endif +DECL_TEMPLATE(freebsd, sys_extattr_set_fd) // 371 +DECL_TEMPLATE(freebsd, sys_extattr_get_fd) // 372 +DECL_TEMPLATE(freebsd, sys_extattr_delete_fd) // 373 +DECL_TEMPLATE(freebsd, sys___setugid) // 374 +DECL_TEMPLATE(freebsd, sys_eaccess) // 376 +// unimpl afs3_syscall 377 +DECL_TEMPLATE(freebsd, sys_nmount) // 378 +// unimpl __mac_get_proc 384 +// unimpl __mac_set_proc 385 +// unimpl __mac_get_fd 386 +// unimpl __mac_get_file 387 +// unimpl __mac_set_fd 388 +// unimpl __mac_set_file 389 +DECL_TEMPLATE(freebsd, sys_kenv) // 390 +DECL_TEMPLATE(freebsd, sys_lchflags) // 391 +DECL_TEMPLATE(freebsd, sys_uuidgen) // 392 +DECL_TEMPLATE(freebsd, sys_sendfile) // 292 + +#if (FREEBSD_VERS >= FREEBSD_12) +DECL_TEMPLATE(freebsd, sys_freebsd11_getfsstat) // 395 +DECL_TEMPLATE(freebsd, sys_freebsd11_statfs) // 396 +DECL_TEMPLATE(freebsd, sys_freebsd11_fstatfs) // 397 +DECL_TEMPLATE(freebsd, sys_freebsd11_fhstatfs) // 398 +#else +DECL_TEMPLATE(freebsd, sys_getfsstat) // 395 +DECL_TEMPLATE(freebsd, sys_statfs) // 396 +DECL_TEMPLATE(freebsd, sys_fstatfs) // 397 +DECL_TEMPLATE(freebsd, sys_fhstatfs) // 398 +#endif + +// unimpl ksem_close 400 +// unimpl ksem_post 401 +// unimpl ksem_wait 402 +// unimpl ksem_trywait 403 + +// unimpl ksem_init 404 +// unimpl ksem_open 405 +// unimpl ksem_unlink 406 +// unimpl ksem_getvalue 407 + +// unimpl ksem_destroy 408 +// unimpl __mac_get_pid 409 +// unimpl __mac_get_link 410 +// unimpl __mac_set_link 411 + +DECL_TEMPLATE(freebsd, sys_extattr_set_link) // 412 +DECL_TEMPLATE(freebsd, sys_extattr_get_link) // 413 +DECL_TEMPLATE(freebsd, sys_extattr_delete_link) // 414 +// unimpl __mac_execve 415 + +DECL_TEMPLATE(freebsd, sys_sigaction) // 416 +DECL_TEMPLATE(freebsd, sys_sigreturn) // 417 +DECL_TEMPLATE(freebsd, sys_getcontext) // 421 +DECL_TEMPLATE(freebsd, sys_setcontext) // 422 +DECL_TEMPLATE(freebsd, sys_swapcontext) // 423 +DECL_TEMPLATE(freebsd, sys_swapoff) // 424 +DECL_TEMPLATE(freebsd, sys___acl_get_link) // 425 +DECL_TEMPLATE(freebsd, sys___acl_set_link) // 426 +DECL_TEMPLATE(freebsd, sys___acl_delete_link) // 427 +DECL_TEMPLATE(freebsd, sys___acl_aclcheck_link) // 428 +DECL_TEMPLATE(freebsd, sys_sigwait) // 429 +DECL_TEMPLATE(freebsd, sys_thr_create) // 430 +DECL_TEMPLATE(freebsd, sys_thr_exit) // 431 +DECL_TEMPLATE(freebsd, sys_thr_self) // 432 +DECL_TEMPLATE(freebsd, sys_thr_kill) // 433 +DECL_TEMPLATE(freebsd, sys__umtx_lock) // 434 +DECL_TEMPLATE(freebsd, sys__umtx_unlock) // 435 +DECL_TEMPLATE(freebsd, sys_jail_attach) // 436 +DECL_TEMPLATE(freebsd, sys_extattr_list_fd) // 437 +DECL_TEMPLATE(freebsd, sys_extattr_list_file) // 438 +DECL_TEMPLATE(freebsd, sys_extattr_list_link) // 439 +// unimpl ksem_timedwait 441 +DECL_TEMPLATE(freebsd, sys_thr_suspend) // 442 +DECL_TEMPLATE(freebsd, sys_thr_wake) // 443 +DECL_TEMPLATE(freebsd, sys_kldunloadf) // 444 +// unimpl audit 445 +// unimpl auditon 446 +// unimpl getauid 447 +// unimpl setauid 448 +// unimpl getaudit 449 +// unimpl setaudit 450 +// unimpl getaudit_addr 451 +// unimpl setaudit_addr 452 +// unimpl auditctl 453 +DECL_TEMPLATE(freebsd, sys__umtx_op) // 454 +DECL_TEMPLATE(freebsd, sys_thr_new) // 455 +DECL_TEMPLATE(freebsd, sys_sigqueue) // 455 +DECL_TEMPLATE(freebsd, sys_kmq_open) // 457 +DECL_TEMPLATE(freebsd, sys_kmq_setattr) // 458 +DECL_TEMPLATE(freebsd, sys_kmq_timedreceive) // 459 +DECL_TEMPLATE(freebsd, sys_kmq_timedsend) // 460 +DECL_TEMPLATE(freebsd, sys_kmq_notify) // 461 +DECL_TEMPLATE(freebsd, sys_kmq_unlink) // 462 +DECL_TEMPLATE(freebsd, sys_abort2) // 463 +DECL_TEMPLATE(freebsd, sys_thr_set_name) // 464 +DECL_TEMPLATE(freebsd, sys_aio_fsync) // 465 +DECL_TEMPLATE(freebsd, sys_rtprio_thread) // 466 +DECL_TEMPLATE(freebsd, sys_pread) // 475 +DECL_TEMPLATE(freebsd, sys_pwrite) // 476 +DECL_TEMPLATE(freebsd, sys_mmap) // 477 +DECL_TEMPLATE(freebsd, sys_lseek) // 478 +DECL_TEMPLATE(freebsd, sys_truncate) // 479 +DECL_TEMPLATE(freebsd, sys_ftruncate) // 480 +DECL_TEMPLATE(freebsd, sys_thr_kill2) // 481 +DECL_TEMPLATE(freebsd, sys_shm_open) // 482 +DECL_TEMPLATE(freebsd, sys_shm_unlink) // 483 +DECL_TEMPLATE(freebsd, sys_cpuset) // 484 +DECL_TEMPLATE(freebsd, sys_cpuset_setid) // 485 +DECL_TEMPLATE(freebsd, sys_cpuset_getid) // 486 +DECL_TEMPLATE(freebsd, sys_cpuset_getaffinity) // 487 +DECL_TEMPLATE(freebsd, sys_cpuset_setaffinity) // 488 +DECL_TEMPLATE(freebsd, sys_faccessat) // 489 +DECL_TEMPLATE(freebsd, sys_fchmodat) //490 +DECL_TEMPLATE(freebsd, sys_fchownat) // 491 +DECL_TEMPLATE(freebsd, sys_fexecve) // 492 +#if (FREEBSD_VERS >= FREEBSD_12) +DECL_TEMPLATE(freebsd, sys_freebsd11_fstatat) // 493 +#else +DECL_TEMPLATE(freebsd, sys_fstatat) // 493 +#endif +DECL_TEMPLATE(freebsd, sys_futimesat) // 494 +DECL_TEMPLATE(freebsd, sys_linkat) // 495 +DECL_TEMPLATE(freebsd, sys_mkdirat) // 496 +DECL_TEMPLATE(freebsd, sys_mkfifoat) // 497 + +#if (FREEBSD_VERS >= FREEBSD_12) +DECL_TEMPLATE(freebsd, sys_freebsd11_mknodat) // 498 +#else +DECL_TEMPLATE(freebsd, sys_mknodat) // 498 +#endif + +DECL_TEMPLATE(freebsd, sys_openat) // 499 +DECL_TEMPLATE(freebsd, sys_readlinkat) // 500 +DECL_TEMPLATE(freebsd, sys_renameat) // 501 +DECL_TEMPLATE(freebsd, sys_symlinkat) // 502 +DECL_TEMPLATE(freebsd, sys_unlinkat) // 503 +DECL_TEMPLATE(freebsd, sys_posix_openpt) // 504 +// unimp gssd_syscall 505 +DECL_TEMPLATE(freebsd, sys_jail_get) // 506 +DECL_TEMPLATE(freebsd, sys_jail_set) // 507 +DECL_TEMPLATE(freebsd, sys_jail_remove) // 508 +DECL_TEMPLATE(freebsd, sys_closefrom) // 508 +DECL_TEMPLATE(freebsd, sys___semctl) // 510 +DECL_TEMPLATE(freebsd, sys_msgctl) // 511 +DECL_TEMPLATE(freebsd, sys_shmctl) // 512 +DECL_TEMPLATE(freebsd, sys_lpathconf) // 513 +DECL_TEMPLATE(freebsd, sys_cap_rights_get) // 515 +DECL_TEMPLATE(freebsd, sys_cap_enter) // 516 +DECL_TEMPLATE(freebsd, sys_cap_getmode) // 517 +DECL_TEMPLATE(freebsd, sys_pdfork) // 518 +DECL_TEMPLATE(freebsd, sys_pdkill) // 519 +DECL_TEMPLATE(freebsd, sys_pdgetpid) // 520 +DECL_TEMPLATE(freebsd, sys_pselect) // 522 +DECL_TEMPLATE(freebsd, sys_getloginclass) // 523 +DECL_TEMPLATE(freebsd, sys_setloginclass) // 524 +DECL_TEMPLATE(freebsd, sys_rctl_get_racct) // 525 +DECL_TEMPLATE(freebsd, sys_rctl_get_rules) // 526 +DECL_TEMPLATE(freebsd, sys_rctl_get_limits) // 527 +DECL_TEMPLATE(freebsd, sys_rctl_add_rule) // 528 +DECL_TEMPLATE(freebsd, sys_rctl_remove_rule) // 529 +DECL_TEMPLATE(freebsd, sys_posix_fallocate) // 530 +DECL_TEMPLATE(freebsd, sys_posix_fadvise) // 531 +DECL_TEMPLATE(freebsd, sys_wait6) // 532 +DECL_TEMPLATE(freebsd, sys_cap_rights_limit) // 533 +DECL_TEMPLATE(freebsd, sys_cap_ioctls_limit) // 534 +DECL_TEMPLATE(freebsd, sys_cap_ioctls_get) // 535 +DECL_TEMPLATE(freebsd, sys_cap_fcntls_limit) // 536 +DECL_TEMPLATE(freebsd, sys_cap_fcntls_get) // 537 +DECL_TEMPLATE(freebsd, sys_bindat) // 538 +DECL_TEMPLATE(freebsd, sys_connectat) // 539 +DECL_TEMPLATE(freebsd, sys_chflagsat) // 540 +DECL_TEMPLATE(freebsd, sys_accept4) // 541 +DECL_TEMPLATE(freebsd, sys_pipe2) // 542 +DECL_TEMPLATE(freebsd, sys_aio_mlock) // 543 +DECL_TEMPLATE(freebsd, sys_procctl) // 544 +DECL_TEMPLATE(freebsd, sys_ppoll) // 545 +DECL_TEMPLATE(freebsd, sys_futimens) // 546 +DECL_TEMPLATE(freebsd, sys_utimensat) // 547 +DECL_TEMPLATE(freebsd, sys_fdatasync) // 550 + +#if (FREEBSD_VERS >= FREEBSD_12) + +DECL_TEMPLATE(freebsd, sys_fstat) // 551 +DECL_TEMPLATE(freebsd, sys_fstatat) // 552 +DECL_TEMPLATE(freebsd, sys_fhstat) // 553 +DECL_TEMPLATE(freebsd, sys_getdirentries) // 554 +DECL_TEMPLATE(freebsd, sys_statfs) // 555 +DECL_TEMPLATE(freebsd, sys_fstatfs) // 556 +DECL_TEMPLATE(freebsd, sys_getfsstat) // 557 +DECL_TEMPLATE(freebsd, sys_fhstatfs) // 558 +DECL_TEMPLATE(freebsd, sys_mknodat) // 559 +DECL_TEMPLATE(freebsd, sys_kevent) // 560 +DECL_TEMPLATE(freebsd, sys_cpuset_getdomain) // 561 +DECL_TEMPLATE(freebsd, sys_cpuset_setdomain) // 562 +DECL_TEMPLATE(freebsd, sys_getrandom) // 563 +DECL_TEMPLATE(freebsd, sys_getfhat) // 654 +DECL_TEMPLATE(freebsd, sys_fhlink) // 565 +DECL_TEMPLATE(freebsd, sys_fhlinkat) // 566 +DECL_TEMPLATE(freebsd, sys_fhreadlink) // 567 + +#endif + +#if (FREEBSD_VERS >= FREEBSD_12_2) + +// unimpl __NR_funlinkat 568 +// unimpl __NR_copy_file_range 569 +DECL_TEMPLATE(freebsd, sys___sysctlbyname) // 570 +// unimpl __NR_shm_open2 571 +// unimpl __NR_shm_rename 572 +// unimpl __NR_sigfastblock 573 +// unimpl __NR___realpathat 574 +// unimpl __NR_close_range 575 + +#endif + +#if (FREEBSD_VERS >= FREEBSD_13) + +// unimpl __NR_rpctls_syscall 576 + +#endif + +#if (FREEBSD_VERS >= FREEBSD_14) + +// unimpl __NR___specialfd 577 +// unimpl __NR_aio_writev 578 +// unimpl __NR_aio_readv 579 + +#endif + +DECL_TEMPLATE(freebsd, sys_fake_sigreturn) + +#endif // PRIV_SYSWRAP_FREEBSD_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/syscall-amd64-freebsd.S b/coregrind/m_syswrap/syscall-amd64-freebsd.S new file mode 100644 index 0000000000..414371967f --- /dev/null +++ b/coregrind/m_syswrap/syscall-amd64-freebsd.S @@ -0,0 +1,207 @@ + +/*--------------------------------------------------------------------*/ +/*--- Support for doing system calls. syscall-amd64-freebsd.S ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2008 Julian Seward + jseward@acm.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#include "pub_core_basics_asm.h" + +#if defined(VGP_amd64_freebsd) + +#include "pub_core_vkiscnums_asm.h" +#include "libvex_guest_offsets.h" + + +/*----------------------------------------------------------------*/ +/* + Perform a syscall for the client. This will run a syscall + with the client's specific per-thread signal mask. + + The structure of this function is such that, if the syscall is + interrupted by a signal, we can determine exactly what + execution state we were in with respect to the execution of + the syscall by examining the value of %eip in the signal + handler. This means that we can always do the appropriate + thing to precisely emulate the kernel's signal/syscall + interactions. + + The syscall number is taken from the argument, even though it + should also be in guest_state->guest_RAX. The syscall result + is written back to guest_state->guest_RAX on completion. + + Returns 0 if the syscall was successfully called (even if the + syscall itself failed), or a -ve error code if one of the + sigprocmasks failed (there's no way to determine which one + failed). + + VG_(fixup_guest_state_after_syscall_interrupted) does the + thread state fixup in the case where we were interrupted by a + signal. + + Prototype: + + Int ML_(do_syscall_for_client_WRK( + Int syscallno, // rdi + void* guest_state, // rsi + const vki_sigset_t *sysmask, // rdx + const vki_sigset_t *postmask, // rcx + Int sigsetSzB) // r8 +*/ + +/* from vki_arch.h */ +#define VKI_SIG_SETMASK 3 + +.globl ML_(do_syscall_for_client_WRK) +ML_(do_syscall_for_client_WRK): + /* save callee-saved regs */ + pushq %rbp + movq %rsp, %rbp + pushq %rdi // -8(%rbp) syscallno + pushq %rsi // -16(%rbp) guest_state + pushq %rdx // -24(%rbp) sysmask + pushq %rcx // -32(%rbp) postmask + pushq %r8 // -40(%rbp) sigsetSzB + +1: /* Even though we can't take a signal until the sigprocmask completes, + start the range early. + If eip is in the range [1,2), the syscall hasn't been started yet */ + + /* Set the signal mask which should be current during the syscall. */ + /* Save and restore all 5 arg regs round the call. This is easier + than figuring out the minimal set to save/restore. */ + + movq $__NR_sigprocmask, %rax // syscall # + movq $VKI_SIG_SETMASK, %rdi // how + movq %rdx, %rsi // sysmask + movq %rcx, %rdx // postmask + syscall + + jb 7f /* sigprocmask failed */ + + /* OK, that worked. Now do the syscall proper. */ + + /* 6 register parameters */ + movq -16(%rbp), %r11 /* r11 = VexGuestAMD64State * */ + movq OFFSET_amd64_RDI(%r11), %rdi + movq OFFSET_amd64_RSI(%r11), %rsi + movq OFFSET_amd64_RDX(%r11), %rdx + movq OFFSET_amd64_R10(%r11), %r10 + movq OFFSET_amd64_R8(%r11), %r8 + movq OFFSET_amd64_R9(%r11), %r9 + /* 2 stack parameters plus return address (ignored by syscall) */ + movq OFFSET_amd64_RSP(%r11), %r11 /* r11 = simulated RSP */ + movq 16(%r11), %rax + pushq %rax + movq 8(%r11), %rax + pushq %rax + /* (fake) return address. */ + movq 0(%r11), %rax + pushq %rax + /* syscallno */ + movq -8(%rbp), %rax + + /* If rip==2, then the syscall was either just about + to start, or was interrupted and the kernel was + restarting it. */ +2: syscall +3: /* In the range [3, 4), the syscall result is in %rax, + but hasn't been committed to RAX. */ + + /* stack contents: 3 words for syscall above, plus our prologue */ + setc 0(%rsp) /* stash returned carry flag */ + + movq -16(%rbp), %r11 /* r11 = VexGuestAMD64State * */ + movq %rax, OFFSET_amd64_RAX(%r11) /* save back to RAX */ + movq %rdx, OFFSET_amd64_RDX(%r11) /* save back to RDX */ + + /* save carry flag to VEX */ + xorq %rax, %rax + movb 0(%rsp), %al + movq %rax, %rdi /* arg1 = new flag */ + movq %r11, %rsi /* arg2 = vex state */ + addq $24, %rsp /* remove syscall parameters */ + call LibVEX_GuestAMD64_put_rflag_c + +4: /* Re-block signals. If eip is in [4,5), then the syscall + is complete and we needn't worry about it. */ + + movq $__NR_sigprocmask, %rax // syscall # + movq $VKI_SIG_SETMASK, %rdi // how + movq -32(%rbp), %rsi // postmask + xorq %rdx, %rdx // NULL + syscall + + jb 7f /* sigprocmask failed */ + +5: /* now safe from signals */ + + xorq %rax,%rax + movq -8(%rbp), %rdi + movq -16(%rbp), %rsi + movq -24(%rbp), %rdx + movq -32(%rbp), %rcx + movq -40(%rbp), %r8 + movq %rbp, %rsp + popq %rbp + ret + +7: /* failure: return 0x8000 | error code */ + orq $0x8000, %rax + movq -8(%rbp), %rdi + movq -16(%rbp), %rsi + movq -24(%rbp), %rdx + movq -32(%rbp), %rcx + movq -40(%rbp), %r8 + movq %rbp, %rsp + popq %rbp + ret + +.section .rodata +/* export the ranges so that + VG_(fixup_guest_state_after_syscall_interrupted) can do the + right thing */ + +.globl ML_(blksys_setup) +.globl ML_(blksys_restart) +.globl ML_(blksys_complete) +.globl ML_(blksys_committed) +.globl ML_(blksys_finished) +ML_(blksys_setup): .quad 1b +ML_(blksys_restart): .quad 2b +ML_(blksys_complete): .quad 3b +ML_(blksys_committed): .quad 4b +ML_(blksys_finished): .quad 5b +.previous + +#endif /* defined(VGP_amd64_freebsd) */ + +/* Let the linker know we don't need an executable stack */ +MARK_STACK_NO_EXEC + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/syscall-x86-freebsd.S b/coregrind/m_syswrap/syscall-x86-freebsd.S new file mode 100644 index 0000000000..9437a34675 --- /dev/null +++ b/coregrind/m_syswrap/syscall-x86-freebsd.S @@ -0,0 +1,201 @@ + +/*--------------------------------------------------------------------*/ +/*--- Support for doing system calls. syscall-x86-freebsd.S ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2007 Julian Seward + jseward@acm.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#include "pub_core_basics_asm.h" + +#if defined(VGP_x86_freebsd) + +#include "pub_core_vkiscnums_asm.h" +#include "libvex_guest_offsets.h" + + +/*----------------------------------------------------------------*/ +/* + Perform a syscall for the client. This will run a syscall + with the client's specific per-thread signal mask. + + The structure of this function is such that, if the syscall is + interrupted by a signal, we can determine exactly what + execution state we were in with respect to the execution of + the syscall by examining the value of %eip in the signal + handler. This means that we can always do the appropriate + thing to precisely emulate the kernel's signal/syscall + interactions. + + The syscall number is taken from the argument, even though it + should also be in regs->m_eax. The syscall result is written + back to regs->m_eax on completion. + + Returns 0 if the syscall was successfully called (even if the + syscall itself failed), or a -ve error code if one of the + sigprocmasks failed (there's no way to determine which one + failed). + + VG_(fixup_guest_state_after_syscall_interrupted) does the + thread state fixup in the case where we were interrupted by a + signal. + + Prototype: + + Int ML_(do_syscall_for_client_WRK)( + Int syscallno, // ebp+8 + void* guest_state, // ebp+12 + const vki_sigset_t *sysmask, // ebp+16 + const vki_sigset_t *postmask, // ebp+20 + Int sigsetSzB) // ebp+24 + + Note that sigsetSzB is totally ignored (and irrelevant). +*/ + +/* from vki-darwin.h, checked at startup by m_vki.c */ +#define VKI_SIG_SETMASK 3 + +.globl ML_(do_syscall_for_client_WRK) +ML_(do_syscall_for_client_WRK): + /* establish stack frame */ + push %ebp + mov %esp, %ebp + subl $8, %esp /* 16-byte align stack */ + +1: /* Even though we can't take a signal until the + sigprocmask completes, start the range early. + If eip is in the range [1,2), the syscall hasn't been started yet */ + + /* Set the signal mask which should be current during the syscall. */ + pushl 20(%ebp) + pushl 16(%ebp) + pushl $VKI_SIG_SETMASK + pushl $0xcafebabe /* totally fake return address */ + movl $__NR_sigprocmask, %eax + int $0x80 + jc 7f /* sigprocmask failed */ + addl $16,%esp + + /* Copy syscall parameters to the stack - assume no more than 8 + * plus the return address */ + /* do_syscall8 */ + /* stack is currently aligned assuming 8 parameters */ + movl 12(%ebp), %edx + movl OFFSET_x86_ESP(%edx), %edx /* edx = simulated ESP */ + movl 28+4(%edx), %eax + pushl %eax + movl 24+4(%edx), %eax + pushl %eax + movl 20+4(%edx), %eax + pushl %eax + movl 16+4(%edx), %eax + pushl %eax + movl 12+4(%edx), %eax + pushl %eax + movl 8+4(%edx), %eax + pushl %eax + movl 4+4(%edx), %eax + pushl %eax + movl 0+4(%edx), %eax + pushl %eax + /* return address */ + movl 0(%edx), %eax + pushl %eax + + /* Put syscall number in eax */ + movl 8(%ebp), %eax + + /* If eip==2, then the syscall was either just about to start, + or was interrupted and the kernel was restarting it. */ +2: int $0x80 /* UNIX (GrP fixme should be sysenter?) */ + +3: /* In the range [3, 4), the syscall result is in %eax and %edx and C, + but hasn't been committed to the thread state. */ + setc 0(%esp) /* stash returned carry flag */ + movl 12(%ebp), %ecx + movl %eax, OFFSET_x86_EAX(%ecx) /* save EAX to vex */ + movl %edx, OFFSET_x86_EDX(%ecx) /* save EDX to vex */ + /* save carry flag to vex */ + subl $12, %esp + movl %ecx, 4(%esp) + movl $0, 0(%esp) + movb 12(%esp), %al + movb %al, 0(%esp) + call LibVEX_GuestX86_put_eflag_c + addl $12, %esp + +4: /* Re-block signals. If eip is in [4,5), then the syscall is + complete and we needn't worry about it. */ + /* Set up for __pthread_sigmask(SIG_SETMASK, postmask, NULL) */ + pushl $0 + pushl 20(%ebp) + pushl $VKI_SIG_SETMASK + pushl $0xcafef00d /* totally fake return address */ + movl $__NR_sigprocmask, %eax + int $0x80 /* should be sysenter? */ + jc 7f /* sigprocmask failed */ + addl $16,%esp + +5: /* now safe from signals */ + movl $0, %eax /* SUCCESS */ + movl %ebp, %esp + popl %ebp + ret + +7: /* failure: return 0x8000 | error code */ + /* Note that we enter here with %esp being 16 too low + (4 extra words on the stack). But because we're nuking + the stack frame now, that doesn't matter. */ + andl $0x7FFF, %eax + orl $0x8000, %eax + movl %ebp, %esp + popl %ebp + ret + +.section .rodata +/* export the ranges so that + VG_(fixup_guest_state_after_syscall_interrupted) can do the + right thing */ + +.globl ML_(blksys_setup) +.globl ML_(blksys_restart) +.globl ML_(blksys_complete) +.globl ML_(blksys_committed) +.globl ML_(blksys_finished) +ML_(blksys_setup): .long 1b +ML_(blksys_restart): .long 2b +ML_(blksys_complete): .long 3b +ML_(blksys_committed): .long 4b +ML_(blksys_finished): .long 5b +.previous + +#endif // defined(VGP_x86_freebsd) + +/* Let the linker know we don't need an executable stack */ +MARK_STACK_NO_EXEC + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/syswrap-amd64-freebsd.c b/coregrind/m_syswrap/syswrap-amd64-freebsd.c new file mode 100644 index 0000000000..24226fa17c --- /dev/null +++ b/coregrind/m_syswrap/syswrap-amd64-freebsd.c @@ -0,0 +1,1113 @@ + +/*--------------------------------------------------------------------*/ +/*--- Platform-specific syscalls stuff. syswrap-amd64-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2005 Nicholas Nethercote + njn@valgrind.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_amd64_freebsd) + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_vkiscnums.h" +#include "pub_core_threadstate.h" +#include "pub_core_aspacemgr.h" +#include "pub_core_debuglog.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcprint.h" +#include "pub_core_libcproc.h" +#include "pub_core_libcsignal.h" +#include "pub_core_machine.h" +#include "pub_core_options.h" +#include "pub_core_scheduler.h" +#include "pub_core_sigframe.h" +#include "pub_core_signals.h" +#include "pub_core_syscall.h" +#include "pub_core_syswrap.h" +#include "pub_core_tooliface.h" +#include "pub_core_stacks.h" // VG_(register_stack) + +#include "priv_types_n_macros.h" +#include "priv_syswrap-generic.h" /* for decls of generic wrappers */ +#include "priv_syswrap-freebsd.h" /* for decls of freebsd-ish wrappers */ +#include "priv_syswrap-main.h" + +/* --------------------------------------------------------------------- + clone() handling + ------------------------------------------------------------------ */ + +/* Call f(arg1), but first switch stacks, using 'stack' as the new + stack, and use 'retaddr' as f's return-to address. Also, clear all + the integer registers before entering f. */ +__attribute__((noreturn)) +void ML_(call_on_new_stack_0_1) ( Addr stack, + Addr retaddr, + void (*f)(Word), + Word arg1 ); +// %rdi == stack +// %rsi == retaddr +// %rdx == f +// %rcx == arg1 +asm( + ".text\n" + ".globl vgModuleLocal_call_on_new_stack_0_1\n" + "vgModuleLocal_call_on_new_stack_0_1:\n" + " movq %rdi, %rsp\n" // set stack + " pushq %rsi\n" // retaddr to stack + " pushq %rdx\n" // f to stack + " pushq %rcx\n" // arg1 to stack + " movq $0, %rax\n" // zero all GP regs + " movq $0, %rbx\n" + " movq $0, %rcx\n" + " movq $0, %rdx\n" + " movq $0, %rsi\n" + " movq $0, %rdi\n" + " movq $0, %rbp\n" + " movq $0, %r8\n" + " movq $0, %r9\n" + " movq $0, %r10\n" + " movq $0, %r11\n" + " movq $0, %r12\n" + " movq $0, %r13\n" + " movq $0, %r14\n" + " movq $0, %r15\n" + " popq %rdi\n" // arg1 to correct arg reg + " ret\n" // jump to f + " ud2\n" // should never get here + ".previous\n" +); + + +/* --------------------------------------------------------------------- + More thread stuff + ------------------------------------------------------------------ */ + +void VG_(cleanup_thread) ( ThreadArchState *arch ) +{ +} + +/* --------------------------------------------------------------------- + PRE/POST wrappers for amd64/FreeBSD-specific syscalls + ------------------------------------------------------------------ */ + +#define PRE(name) DEFN_PRE_TEMPLATE(freebsd, name) +#define POST(name) DEFN_POST_TEMPLATE(freebsd, name) + +// SYS_sysarch 165 +// int sysarch(int number, void *args); +PRE(sys_sysarch) +{ + ThreadState *tst; + void **p; + + PRINT("sys_sysarch ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2); + PRE_REG_READ2(int, "sysarch", int, number, void *, args); + switch (ARG1) { + case VKI_AMD64_SET_FSBASE: + PRINT("sys_amd64_set_fsbase ( %#lx )", ARG2); + + if (ML_(safe_to_deref)((void**)ARG2, sizeof(void*))) { + /* On FreeBSD, the syscall loads the %gs selector for us, so do it now. */ + tst = VG_(get_ThreadState)(tid); + p = (void**)ARG2; + tst->arch.vex.guest_FS_CONST = (UWord)*p; + /* "do" the syscall ourselves; the kernel never sees it */ + SET_STATUS_Success2((ULong)*p, tst->arch.vex.guest_RDX ); + } else { + // ???? + SET_STATUS_Failure( VKI_EINVAL ); + } + + break; + case VKI_AMD64_GET_FSBASE: + PRINT("sys_amd64_get_fsbase ( %#lx )", ARG2); + PRE_MEM_WRITE( "amd64_get_fsbase(basep)", ARG2, sizeof(void *) ); + if (ML_(safe_to_deref)((void**)ARG2, sizeof(void*))) { + /* "do" the syscall ourselves; the kernel never sees it */ + tst = VG_(get_ThreadState)(tid); + SET_STATUS_Success2( tst->arch.vex.guest_FS_CONST, tst->arch.vex.guest_RDX ); + } else { + SET_STATUS_Failure( VKI_EINVAL ); + } + break; + case VKI_AMD64_GET_XFPUSTATE: + PRINT("sys_amd64_get_xfpustate ( %#lx )", ARG2); + PRE_MEM_WRITE( "amd64_get_xfpustate(basep)", ARG2, sizeof(void *) ); + + // @todo PJF need a test for this + // I think that it will fail in the POST if ARG2 is not a valid pointer + + /* "do" the syscall ourselves; the kernel never sees it */ + tst = VG_(get_ThreadState)(tid); + SET_STATUS_Success2( tst->arch.vex.guest_FPTAG[0], tst->arch.vex.guest_FPTAG[0] ); + break; + default: + VG_(message) (Vg_UserMsg, "unhandled sysarch cmd %lu", ARG1); + VG_(unimplemented) ("unhandled sysarch cmd"); + break; + } +} + +POST(sys_sysarch) +{ + switch (ARG1) { + case VKI_AMD64_SET_FSBASE: + break; + case VKI_AMD64_GET_FSBASE: + POST_MEM_WRITE( ARG2, sizeof(void *) ); + break; + case VKI_AMD64_GET_XFPUSTATE: + POST_MEM_WRITE( ARG2, sizeof(void *) ); + break; + default: + break; + } +} + +// freebsd6_pread 173 +#if (FREEBSD_VERS <= FREEBSD_10) +PRE(sys_freebsd6_pread) +{ + *flags |= SfMayBlock; + PRINT("sys_freebsd6_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %lu, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4, ARG5); + PRE_REG_READ5(ssize_t, "read", + unsigned int, fd, char *, buf, vki_size_t, count, + int, pad, unsigned long, off); + + if (!ML_(fd_allowed)(ARG1, "freebsd6_pread", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_WRITE( "freebsd6_pread(buf)", ARG2, ARG3 ); +} + +POST(sys_freebsd6_pread) +{ + vg_assert(SUCCESS); + POST_MEM_WRITE( ARG2, RES ); +} +#endif + +// freebsd6_pwrite 174 +#if (FREEBSD_VERS <= FREEBSD_10) +PRE(sys_freebsd6_pwrite) +{ + Bool ok; + *flags |= SfMayBlock; + PRINT("sys_freebsd6_pwrite ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", SARG1, ARG2, ARG3, ARG4, ARG5); + PRE_REG_READ5(ssize_t, "write", + unsigned int, fd, const char *, buf, vki_size_t, count, + int, pad, unsigned long, off); + /* check to see if it is allowed. If not, try for an exemption from + --sim-hints=enable-outer (used for self hosting). */ + ok = ML_(fd_allowed)(ARG1, "freebsd6_pwrite", tid, False); + if (!ok && ARG1 == 2/*stderr*/ + && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints))) + ok = True; + if (!ok) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_READ( "freebsd6_pwrite(buf)", ARG2, ARG3 ); +} +#endif + +// SYS_freebsd6_mmap 197 +#if (FREEBSD_VERS <= FREEBSD_10) +/* This is here because on x86 the off_t is passed in 2 regs. Don't ask about pad. */ + +/* caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); */ +/* ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7 */ + +PRE(sys_freebsd6_mmap) +{ + SysRes r; + + PRINT("sys_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, pad%" FMT_REGWORD "u, 0x%" FMT_REGWORD "x)", + ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, ARG6, ARG7 ); + PRE_REG_READ7(long, "mmap", + char *, addr, unsigned long, len, int, prot, int, flags, + int, fd, int, pad, unsigned long, pos); + + r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG7 ); + SET_STATUS_from_SysRes(r); +} +#endif + +// freebsd6_lseek 199 +#if (FREEBSD_VERS <= FREEBSD_10) +PRE(sys_freebsd6_lseek) +{ + PRINT("sys_freebsd6_lseek ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "lseek", + unsigned int, fd, int, pad, unsigned long, offset, + unsigned int, whence); +} +#endif + +// freebsd6_truncate 200 +#if (FREEBSD_VERS <= FREEBSD_10) +PRE(sys_freebsd6_truncate) +{ + *flags |= SfMayBlock; + PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG3); + PRE_REG_READ3(long, "truncate", + const char *, path, int, pad, unsigned int, length); + PRE_MEM_RASCIIZ( "truncate(path)", ARG1 ); +} +#endif + +// freebsd6_ftruncate 201 +#if (FREEBSD_VERS <= FREEBSD_10) +PRE(sys_freebsd6_ftruncate) +{ + *flags |= SfMayBlock; + PRINT("sys_ftruncate ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG3); + PRE_REG_READ3(long, "ftruncate", unsigned int, fd, int, pad, + unsigned int, length); +} +#endif + +// SYS_rfork 251 +// pid_t rfork(int flags); +PRE(sys_rfork) +{ + PRINT("sys_rfork ( %#" FMT_REGWORD "x )", ARG1 ); + PRE_REG_READ1(long, "rfork", int, flags); + + VG_(message)(Vg_UserMsg, "rfork() not implemented"); + VG_(unimplemented)("Valgrind does not support rfork()."); + + SET_STATUS_Failure(VKI_ENOSYS); +} + +// SYS_preadv 289 +// ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); +PRE(sys_preadv) +{ + Int i; + struct vki_iovec * vec; + *flags |= SfMayBlock; + PRINT("sys_preadv ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" + FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1, ARG2, SARG3, SARG4); + PRE_REG_READ4(ssize_t, "preadv", + int, fd, const struct iovec *, iovr, + int, iovcnt, vki_off_t, offset); + if (!ML_(fd_allowed)(ARG1, "preadv", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } else { + if ((Int)ARG3 >= 0) + PRE_MEM_READ( "preadv(iov)", ARG2, ARG3 * sizeof(struct vki_iovec) ); + + if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) { + vec = (struct vki_iovec *)(Addr)ARG2; + for (i = 0; i < (Int)ARG3; i++) + PRE_MEM_WRITE( "preadv(iov[...])", + (Addr)vec[i].iov_base, vec[i].iov_len ); + } + } +} + +POST(sys_preadv) +{ + vg_assert(SUCCESS); + if (RES > 0) { + Int i; + struct vki_iovec * vec = (struct vki_iovec *)(Addr)ARG2; + Int remains = RES; + + /* RES holds the number of bytes read. */ + for (i = 0; i < (Int)ARG3; i++) { + Int nReadThisBuf = vec[i].iov_len; + if (nReadThisBuf > remains) nReadThisBuf = remains; + POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf ); + remains -= nReadThisBuf; + if (remains < 0) VG_(core_panic)("preadv: remains < 0"); + } + } +} + +// SYS_pwritev 290 +// ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); +PRE(sys_pwritev) +{ + Int i; + struct vki_iovec * vec; + *flags |= SfMayBlock; + PRINT("sys_pwritev ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" + FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1, ARG2, SARG3, SARG4); + + PRE_REG_READ4(ssize_t, "pwritev", + int, fd, const struct iovec *, iov, + int, iovcnt, + vki_off_t, offset); + if (!ML_(fd_allowed)(ARG1, "pwritev", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } else { + if ((Int)ARG3 >= 0) + PRE_MEM_READ( "pwritev(vector)", ARG2, ARG3 * sizeof(struct vki_iovec) ); + if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) { + vec = (struct vki_iovec *)(Addr)ARG2; + for (i = 0; i < (Int)ARG3; i++) + PRE_MEM_READ( "pwritev(iov[...])", + (Addr)vec[i].iov_base, vec[i].iov_len ); + } + } +} + +// SYS_sendfile 393 +// int sendfile(int fd, int s, off_t offset, size_t nbytes, +// struct sf_hdtr *hdtr, off_t *sbytes, int flags); +PRE(sys_sendfile) +{ + *flags |= SfMayBlock; + + PRINT("sys_sendfile ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %lu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )", + SARG1,SARG2,ARG3,ARG4,ARG5,ARG6,SARG7); + PRE_REG_READ7(int, "sendfile", + int, fd, int, s, vki_off_t, offset, size_t, nbytes, + void *, hdtr, vki_off_t *, sbytes, int, flags); + + if (ARG5 != 0) + PRE_MEM_READ("sendfile(hdtr)", ARG5, sizeof(struct vki_sf_hdtr)); + + if (ARG6 != 0) + PRE_MEM_WRITE( "sendfile(sbytes)", ARG6, sizeof(vki_off_t) ); +} + +POST(sys_sendfile) +{ + if (ARG6 != 0 ) { + POST_MEM_WRITE( ARG6, sizeof( vki_off_t ) ); + } +} + +// SYS_sigreturn 417 +// int sigreturn(const ucontext_t *scp); +PRE(sys_sigreturn) +{ + PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "sigreturn", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); +} + +static void restore_mcontext(ThreadState *tst, struct vki_mcontext *sc) +{ + tst->arch.vex.guest_RAX = sc->rax; + tst->arch.vex.guest_RCX = sc->rcx; + tst->arch.vex.guest_RDX = sc->rdx; + tst->arch.vex.guest_RBX = sc->rbx; + tst->arch.vex.guest_RBP = sc->rbp; + tst->arch.vex.guest_RSP = sc->rsp; + tst->arch.vex.guest_RSI = sc->rsi; + tst->arch.vex.guest_RDI = sc->rdi; + tst->arch.vex.guest_R8 = sc->r8; + tst->arch.vex.guest_R9 = sc->r9; + tst->arch.vex.guest_R10 = sc->r10; + tst->arch.vex.guest_R11 = sc->r11; + tst->arch.vex.guest_R12 = sc->r12; + tst->arch.vex.guest_R13 = sc->r13; + tst->arch.vex.guest_R14 = sc->r14; + tst->arch.vex.guest_R15 = sc->r15; + tst->arch.vex.guest_RIP = sc->rip; + /* + * XXX: missing support for other flags. + */ + if (sc->rflags & 0x0001) + LibVEX_GuestAMD64_put_rflag_c(1, &tst->arch.vex); + else + LibVEX_GuestAMD64_put_rflag_c(0, &tst->arch.vex); +} + +static void fill_mcontext(ThreadState *tst, struct vki_mcontext *sc) +{ + sc->rax = tst->arch.vex.guest_RAX; + sc->rcx = tst->arch.vex.guest_RCX; + sc->rdx = tst->arch.vex.guest_RDX; + sc->rbx = tst->arch.vex.guest_RBX; + sc->rbp = tst->arch.vex.guest_RBP; + sc->rsp = tst->arch.vex.guest_RSP; + sc->rsi = tst->arch.vex.guest_RSI; + sc->rdi = tst->arch.vex.guest_RDI; + sc->r8 = tst->arch.vex.guest_R8; + sc->r9 = tst->arch.vex.guest_R9; + sc->r10 = tst->arch.vex.guest_R10; + sc->r11 = tst->arch.vex.guest_R11; + sc->r12 = tst->arch.vex.guest_R12; + sc->r13 = tst->arch.vex.guest_R13; + sc->r14 = tst->arch.vex.guest_R14; + sc->r15 = tst->arch.vex.guest_R15; + sc->rip = tst->arch.vex.guest_RIP; + /* + Not supported by VEX. + sc->cs = tst->arch.vex.guest_CS; + sc->ss = tst->arch.vex.guest_SS; + sc->ds = tst->arch.vex.guest_DS; + sc->es = tst->arch.vex.guest_ES; + sc->fs = tst->arch.vex.guest_FS; + sc->gs = tst->arch.vex.guest_GS; + */ + sc->rflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex); + /* + not yet. + VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate)); + */ + sc->fpformat = VKI_FPFMT_NODEV; + sc->ownedfp = VKI_FPOWNED_NONE; + sc->len = sizeof(*sc); + VG_(memset)(sc->spare2, 0, sizeof(sc->spare2)); +} + +// SYS_getcontext 421 +// int getcontext(ucontext_t *ucp); +PRE(sys_getcontext) +{ + ThreadState* tst; + struct vki_ucontext *uc; + + PRINT("sys_getcontext ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "getcontext", + struct vki_ucontext *, ucp); + PRE_MEM_WRITE( "getcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + uc = (struct vki_ucontext *)ARG1; + if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext))) { + SET_STATUS_Failure(VKI_EFAULT); + return; + } + tst = VG_(get_ThreadState)(tid); + fill_mcontext(tst, &uc->uc_mcontext); + uc->uc_mcontext.rax = 0; + uc->uc_mcontext.rdx = 0; + uc->uc_mcontext.rflags &= ~0x0001; /* PSL_C */ + uc->uc_sigmask = tst->sig_mask; + VG_(memset)(uc->__spare__, 0, sizeof(uc->__spare__)); + SET_STATUS_Success(0); +} + +// SYS_setcontext 422 +// int setcontext(const ucontext_t *ucp); +PRE(sys_setcontext) +{ + ThreadState* tst; + struct vki_ucontext *uc; + + PRINT("sys_setcontext ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(long, "setcontext", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(tid >= 1 && tid < VG_N_THREADS); + vg_assert(VG_(is_running_thread)(tid)); + + tst = VG_(get_ThreadState)(tid); + uc = (struct vki_ucontext *)ARG1; + if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext)) || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) { + SET_STATUS_Failure(VKI_EFAULT); + return; + } + + restore_mcontext(tst, &uc->uc_mcontext); + tst->sig_mask = uc->uc_sigmask; + tst->tmp_sig_mask = uc->uc_sigmask; + + /* Tell the driver not to update the guest state with the "result", + and set a bogus result to keep it happy. */ + *flags |= SfNoWriteResult; + SET_STATUS_Success(0); + + /* Check to see if some any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + +// SYS_swapcontext 423 +// int swapcontext(ucontext_t *oucp, const ucontext_t *ucp); +PRE(sys_swapcontext) +{ + struct vki_ucontext *ucp, *oucp; + ThreadState* tst; + + PRINT("sys_swapcontext ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2); + PRE_REG_READ2(long, "swapcontext", + struct vki_ucontext *, oucp, struct vki_ucontext *, ucp); + + PRE_MEM_READ( "swapcontext(ucp)", ARG2, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "swapcontext(oucp)", ARG1, sizeof(struct vki_ucontext) ); + + oucp = (struct vki_ucontext *)ARG1; + ucp = (struct vki_ucontext *)ARG2; + if (!ML_(safe_to_deref)(oucp, sizeof(struct vki_ucontext)) || + !ML_(safe_to_deref)(ucp, sizeof(struct vki_ucontext)) || + ucp->uc_mcontext.len != sizeof(ucp->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + tst = VG_(get_ThreadState)(tid); + + /* + * Save the context. + */ + fill_mcontext(tst, &oucp->uc_mcontext); + oucp->uc_mcontext.rax = 0; + oucp->uc_mcontext.rdx = 0; + oucp->uc_mcontext.rflags &= ~0x0001; /* PSL_C */ + oucp->uc_sigmask = tst->sig_mask; + VG_(memset)(oucp->__spare__, 0, sizeof(oucp->__spare__)); + + /* + * Switch to new one. + */ + restore_mcontext(tst, &ucp->uc_mcontext); + tst->sig_mask = ucp->uc_sigmask; + tst->tmp_sig_mask = ucp->uc_sigmask; + + /* Tell the driver not to update the guest state with the "result", + and set a bogus result to keep it happy. */ + *flags |= SfNoWriteResult; + SET_STATUS_Success(0); + + /* Check to see if some any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + +// SYS_thr_new 455 +// int thr_new(struct thr_param *param, int param_size); +PRE(sys_thr_new) +{ + static const Bool debug = False; + + ThreadId ctid = VG_(alloc_ThreadState)(); + ThreadState* ptst = VG_(get_ThreadState)(tid); + ThreadState* ctst = VG_(get_ThreadState)(ctid); + SysRes res; + vki_sigset_t blockall, savedmask; + struct vki_thr_param tp; + Addr stk; + + PRINT("thr_new ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2); + PRE_REG_READ2(int, "thr_new", + struct thr_param *, param, + int, param_size); + + PRE_MEM_READ( "thr_new(param)", ARG1, offsetof(struct vki_thr_param, spare)); + if (!ML_(safe_to_deref)( (void*)ARG1, offsetof(struct vki_thr_param, spare))) { + SET_STATUS_Failure( VKI_EFAULT ); + return; + } + VG_(memset)(&tp, 0, sizeof(tp)); + VG_(memcpy)(&tp, (void *)ARG1, offsetof(struct vki_thr_param, spare)); + PRE_MEM_WRITE("thr_new(parent_tidptr)", (Addr)tp.parent_tid, sizeof(long)); + PRE_MEM_WRITE("thr_new(child_tidptr)", (Addr)tp.child_tid, sizeof(long)); + + VG_(sigfillset)(&blockall); + + vg_assert(VG_(is_running_thread)(tid)); + vg_assert(VG_(is_valid_tid)(ctid)); + + /* Copy register state + + On linux, both parent and child return to the same place, and the code + following the clone syscall works out which is which, so we + don't need to worry about it. + On FreeBSD, thr_new arranges a direct call. We don't actually need any + of this gunk. + + The parent gets the child's new tid returned from clone, but the + child gets 0. + + If the clone call specifies a NULL rsp for the new thread, then + it actually gets a copy of the parent's rsp. + */ + /* We inherit our parent's guest state. */ + ctst->arch.vex = ptst->arch.vex; + ctst->arch.vex_shadow1 = ptst->arch.vex_shadow1; + ctst->arch.vex_shadow2 = ptst->arch.vex_shadow2; + + /* Make thr_new appear to have returned Success(0) in the + child. */ + ctst->arch.vex.guest_RAX = 0; + ctst->arch.vex.guest_RDX = 0; + LibVEX_GuestAMD64_put_rflag_c(0, &ctst->arch.vex); + + ctst->os_state.parent = tid; + + /* inherit signal mask */ + ctst->sig_mask = ptst->sig_mask; + ctst->tmp_sig_mask = ptst->sig_mask; + + /* Linux has to guess, we don't */ + ctst->client_stack_highest_byte = (Addr)tp.stack_base + tp.stack_size; + ctst->client_stack_szB = tp.stack_size; + ctst->os_state.stk_id = VG_(register_stack)((Addr)tp.stack_base, (Addr)tp.stack_base + tp.stack_size); + + /* Assume the thr_new will succeed, and tell any tool that wants to + know that this thread has come into existence. If the thr_new + fails, we'll send out a ll_exit notification for it at the out: + label below, to clean up. */ + VG_TRACK ( pre_thread_ll_create, tid, ctid ); + + if (debug) + VG_(printf)("clone child has SETTLS: tls at %#lx\n", (Addr)tp.tls_base); + ctst->arch.vex.guest_FS_CONST = (UWord)tp.tls_base; + tp.tls_base = 0; /* Don't have the kernel do it too */ + + /* start the thread with everything blocked */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask); + + /* Set the client state for scheduler to run libthr's trampoline */ + ctst->arch.vex.guest_RDI = (Addr)tp.arg; + /* XXX: align on 16-byte boundary? */ + ctst->arch.vex.guest_RSP = (Addr)tp.stack_base + tp.stack_size - 8; + ctst->arch.vex.guest_RIP = (Addr)tp.start_func; + + /* But this is for thr_new() to run valgrind's trampoline */ + tp.start_func = (void *)ML_(start_thread_NORETURN); + tp.arg = &VG_(threads)[ctid]; + + /* And valgrind's trampoline on its own stack */ + stk = ML_(allocstack)(ctid); + if (stk == (Addr)NULL) { + res = VG_(mk_SysRes_Error)( VKI_ENOMEM ); + goto fail; + } + tp.stack_base = (void *)ctst->os_state.valgrind_stack_base; + tp.stack_size = (Addr)stk - (Addr)tp.stack_base; + + /* Create the new thread */ + res = VG_(do_syscall2)(__NR_thr_new, (UWord)&tp, sizeof(tp)); + + VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL); + +fail: + if (sr_isError(res)) { + /* thr_new failed */ + VG_(cleanup_thread)(&ctst->arch); + ctst->status = VgTs_Empty; + /* oops. Better tell the tool the thread exited in a hurry :-) */ + VG_TRACK( pre_thread_ll_exit, ctid ); + } else { + + POST_MEM_WRITE((Addr)tp.parent_tid, sizeof(long)); + POST_MEM_WRITE((Addr)tp.child_tid, sizeof(long)); + + /* Thread creation was successful; let the child have the chance + to run */ + *flags |= SfYieldAfter; + } + + /* "Complete" the syscall so that the wrapper doesn't call the kernel again. */ + SET_STATUS_from_SysRes(res); +} + +// SYS_pread 475 +// ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset); +PRE(sys_pread) +{ + *flags |= SfMayBlock; + PRINT("sys_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4); + PRE_REG_READ4(ssize_t, "pread", + unsigned int, fd, char *, buf, vki_size_t, count, + unsigned long, off); + + if (!ML_(fd_allowed)(ARG1, "read", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_WRITE( "pread(buf)", ARG2, ARG3 ); +} + +POST(sys_pread) +{ + vg_assert(SUCCESS); + POST_MEM_WRITE( ARG2, RES ); +} + +// SYS_pwrite 476 +// ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset); +PRE(sys_pwrite) +{ + Bool ok; + *flags |= SfMayBlock; + PRINT("sys_pwrite ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4); + PRE_REG_READ4(ssize_t, "pwrite", + int, fd, const char *, buf, vki_size_t, nbytes, + vki_off_t, offset); + /* check to see if it is allowed. If not, try for an exemption from + --sim-hints=enable-outer (used for self hosting). */ + ok = ML_(fd_allowed)(ARG1, "pwrite", tid, False); + if (!ok && ARG1 == 2/*stderr*/ + && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints))) + ok = True; + if (!ok) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_READ( "pwrite(buf)", ARG2, ARG3 ); +} + +// SYS_mmap 477 +/* FreeBSD-7 introduces a "regular" version of mmap etc. */ +// void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); +PRE(sys_mmap) +{ + SysRes r; + + PRINT("sys_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x)", + ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, ARG6 ); + PRE_REG_READ6(void *, "mmap", + void *, addr, size_t, len, int, prot, int, flags, + int, fd, off_t, offset); + + r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 ); + SET_STATUS_from_SysRes(r); +} + +// SYS_lseek 478 +// off_t lseek(int fildes, off_t offset, int whence); +PRE(sys_lseek) +{ + PRINT("sys_lseek ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "lseek", + unsigned int, fd, unsigned long, offset, + unsigned int, whence); +} + +// SYS_truncate 479 +// int truncate(const char *path, off_t length); +PRE(sys_truncate) +{ + *flags |= SfMayBlock; + PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "truncate", + const char *, path, unsigned long, length); + PRE_MEM_RASCIIZ( "truncate(path)", ARG1 ); +} + +// SYS_ftruncate 480 +// int ftruncate(int fd, off_t length); +PRE(sys_ftruncate) +{ + *flags |= SfMayBlock; + PRINT("sys_ftruncate ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG2); + PRE_REG_READ2(long, "ftruncate", unsigned int, fd, + unsigned long, length); +} + +// SYS_cpuset_setid 485 +// int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid); +PRE(sys_cpuset_setid) +{ + PRINT("sys_cpuset_setid ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", + SARG1, SARG2, ARG3); + PRE_REG_READ3(int, "cpuset_setid", vki_cpuwhich_t, which, vki_id_t, id, + vki_cpusetid_t *,setid); +} + +// SYS_cpuset_getid 486 +// int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id, +// cpusetid_t *setid); +PRE(sys_cpuset_getid) +{ + PRINT("sys_cpuset_getid ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", + SARG1, SARG2, SARG3, ARG4); + PRE_REG_READ4(int, "cpuset_getid", vki_cpulevel_t, level, + vki_cpuwhich_t, which, vki_id_t, id, + vki_cpusetid_t, setid); + PRE_MEM_WRITE("cpuset_getid(setid)", ARG4, sizeof(vki_cpusetid_t)); +} + +POST(sys_cpuset_getid) +{ + POST_MEM_WRITE(ARG4, sizeof(vki_cpusetid_t)); +} + +// SYS_cpuset_getaffinity 487 +// int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id, +// size_t setsize, cpuset_t *mask); +PRE(sys_cpuset_getaffinity) +{ + PRINT("sys_cpuset_getaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", + ARG1, ARG2, SARG3, ARG4, ARG5); + PRE_REG_READ5(int, "cpuset_getaffinity", + vki_cpulevel_t, level, vki_cpuwhich_t, which, vki_id_t, id, + size_t, setsize, void *, mask); + PRE_MEM_WRITE("cpuset_getaffinity", ARG5, ARG4); +} + +POST(sys_cpuset_getaffinity) +{ + vg_assert(SUCCESS); + if (RES == 0) + POST_MEM_WRITE( ARG5, ARG4 ); +} + +// SYS_cpuset_setaffinity 488 +// int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id, +// size_t setsize, const cpuset_t *mask); +PRE(sys_cpuset_setaffinity) +{ + + PRINT("sys_cpuset_setaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", + ARG1, ARG2, SARG3, ARG4, ARG5); + PRE_REG_READ5(int, "cpuset_setaffinity", + vki_cpulevel_t, level, vki_cpuwhich_t, which, vki_id_t, id, + size_t, setsize, void *, mask); + PRE_MEM_READ("cpuset_setaffinity", ARG5, ARG4); +} + +// SYS_posix_fallocate 530 +// int posix_fallocate(int fd, off_t offset, off_t len); +PRE(sys_posix_fallocate) +{ + PRINT("sys_posix_fallocate ( %" FMT_REGWORD "d, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", + SARG1, ARG2, ARG3); + PRE_REG_READ3(long, "posix_fallocate", + int, fd, vki_off_t, offset, + vki_off_t, len); +} + +// SYS_posix_fadvise 531 +// int posix_fadvise(int fd, off_t offset, off_t len, int advice); +PRE(sys_posix_fadvise) +{ + PRINT("sys_posix_fadvise ( %" FMT_REGWORD "d, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "d )", + SARG1, ARG2, ARG3, SARG4); + PRE_REG_READ4(long, "posix_fadvise", + int, fd, off_t, offset, + off_t, len, + int, advice); + // @todo PJF advice can be 0 to 5 inclusive +} + +// SYS_wait6 532 +// pid_t wait6(idtype_t idtype, id_t id, int *status, int options, +// struct __wrusage *wrusage, siginfo_t *infop); +PRE(sys_wait6) +{ + PRINT("sys_wait6 ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + SARG1, SARG2, ARG3, SARG4, ARG5, ARG6); + PRE_REG_READ6(pid_t, "wait6", vki_idtype_t, idtype, vki_id_t, id, int *, status, int, options, + struct vki___wrusage *, wrusage, vki_siginfo_t *,infop); + PRE_MEM_WRITE("wait6(status)", ARG3, sizeof(int)); + if (ARG5) { + PRE_MEM_WRITE("wait6(wrusage)", ARG5, sizeof(struct vki___wrusage)); + } + if (ARG6) { + PRE_MEM_WRITE("wait6(infop)", ARG6, sizeof(vki_siginfo_t)); + } +} + +POST(sys_wait6) +{ + POST_MEM_WRITE(ARG3, sizeof(int)); + if (ARG5) { + POST_MEM_WRITE(ARG5, sizeof(struct vki___wrusage)); + } + + if (ARG6) { + POST_MEM_WRITE(ARG5, sizeof(vki_siginfo_t)); + } +} + +// the man page is inconsistent for the last argument +// See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=247386 +// will stick to 'arg' for simplicity + +// SYS_procctl 544 +// int procctl(idtype_t idtype, id_t id, int cmd, void *arg); +PRE(sys_procctl) +{ + PRINT("sys_procctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD"d, %#" FMT_REGWORD "x )", + SARG1, SARG2, SARG3, ARG4); + PRE_REG_READ4(int, "procctl", vki_idtype_t, idtype, vki_id_t, id, int, cmd, void *, arg); + switch (ARG3) { + case PROC_ASLR_CTL: + case PROC_SPROTECT: + case PROC_TRACE_CTL: + case PROC_TRAPCAP_CTL: + case PROC_PDEATHSIG_CTL: + case PROC_STACKGAP_CTL: + PRE_MEM_READ("procctl(arg)", ARG4, sizeof(int)); + break; + case PROC_REAP_STATUS: + PRE_MEM_READ("procctl(arg)", ARG4, sizeof(struct vki_procctl_reaper_status)); + break; + case PROC_REAP_GETPIDS: + PRE_MEM_READ("procctl(arg)", ARG4, sizeof(struct vki_procctl_reaper_pids)); + break; + case PROC_REAP_KILL: + /* The first three fields are reads + * int rk_sig; + * u_int rk_flags; + * pid_t rk_subtree; + * + * The last two fields are writes + * u_int rk_killed; + * pid_t rk_fpid; + * + * There is also a pad field + */ + PRE_MEM_READ("procctl(arg)", ARG4, sizeof(int) + sizeof(u_int) + sizeof(vki_pid_t)); + PRE_MEM_WRITE("procctl(arg)", ARG4+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t)); + break; + case PROC_ASLR_STATUS: + case PROC_PDEATHSIG_STATUS: + case PROC_STACKGAP_STATUS: + case PROC_TRAPCAP_STATUS: + case PROC_TRACE_STATUS: + PRE_MEM_WRITE("procctl(arg)", ARG4, sizeof(int)); + case PROC_REAP_ACQUIRE: + case PROC_REAP_RELEASE: + default: + break; + } +} + +POST(sys_procctl) +{ + switch (ARG3) { + case PROC_REAP_KILL: + POST_MEM_WRITE(ARG4+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t)); + break; + case PROC_ASLR_STATUS: + case PROC_PDEATHSIG_STATUS: + case PROC_STACKGAP_STATUS: + case PROC_TRAPCAP_STATUS: + case PROC_TRACE_STATUS: + POST_MEM_WRITE(ARG4, sizeof(int)); + default: + break; + } +} + +#if (FREEBSD_VERS >= FREEBSD_12) + +// SYS_cpuset_getdomain 561 +// int cpuset_getdomain(cpulevel_t level, cpuwhich_t which, id_t id, +// size_t setsize, domainset_t *mask, int *policy); +PRE(sys_cpuset_getdomain) +{ + PRINT("sys_cpuset_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + SARG1, SARG2, SARG3, ARG4, ARG5, ARG6); + PRE_REG_READ6(int, "cpuset_getdomain", + cpulevel_t, level, cpuwhich_t, which, id_t, id, + size_t, setsize, vki_domainset_t *, mask, int *, policy); + // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)" + PRE_MEM_WRITE( "cpuset_getdomain(mask)", ARG5, ARG4 ); + PRE_MEM_WRITE( "cpuset_getdomain(policy)", ARG6, sizeof(int) ); +} + +POST(sys_cpuset_getdomain) +{ + POST_MEM_WRITE(ARG5, ARG4 ); + POST_MEM_WRITE(ARG6, sizeof(int) ); +} + +// SYS_cpuset_setdomain 562 +// int cuset_setdomain(cpulevel_t level, cpuwhich_t which, id_t id, +// size_t setsize, const domainset_t *mask, int policy); +PRE(sys_cpuset_setdomain) +{ + PRINT("sys_cpuget_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )", + SARG1, SARG2, SARG3, ARG4, ARG5, SARG6); + PRE_REG_READ6(int, "cpuset_getdomain", + cpulevel_t, level, cpuwhich_t, which, id_t, id, + size_t, setsize, vki_domainset_t *, mask, int, policy); + // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)" + PRE_MEM_READ( "cpuset_getdomain(mask)", ARG5, ARG4 ); +} + +#endif + +PRE(sys_fake_sigreturn) +{ + ThreadState* tst; + struct vki_ucontext *uc; + int rflags; + + PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(long, "sigreturn", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); + + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(tid >= 1 && tid < VG_N_THREADS); + vg_assert(VG_(is_running_thread)(tid)); + + /* Adjust esp to point to start of frame; skip back up over handler + ret addr */ + tst = VG_(get_ThreadState)(tid); + tst->arch.vex.guest_RSP -= sizeof(Addr); + + uc = (struct vki_ucontext *)ARG1; + if (uc == NULL || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + + /* This is only so that the EIP is (might be) useful to report if + something goes wrong in the sigreturn */ + ML_(fixup_guest_state_to_restart_syscall)(&tst->arch); + + VG_(sigframe_destroy)(tid); + + /* For unclear reasons, it appears we need the syscall to return + without changing %RAX. Since %RAX is the return value, and can + denote either success or failure, we must set up so that the + driver logic copies it back unchanged. Also, note %RAX is of + the guest registers written by VG_(sigframe_destroy). */ + rflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex); + SET_STATUS_from_SysRes( VG_(mk_SysRes_amd64_freebsd)( tst->arch.vex.guest_RAX, + tst->arch.vex.guest_RDX, (rflags & 1) != 0 ? True : False) ); + + /* + * Signal handler might have changed the signal mask. Respect that. + */ + tst->sig_mask = uc->uc_sigmask; + tst->tmp_sig_mask = uc->uc_sigmask; + + /* Tell the driver not to update the guest state with the "result", + and set a bogus result to keep it happy. */ + *flags |= SfNoWriteResult; + SET_STATUS_Success(0); + + /* Check to see if some any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + + +#undef PRE +#undef POST + +#endif /* defined(VGP_amd64_freebsd) */ + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/syswrap-freebsd.c b/coregrind/m_syswrap/syswrap-freebsd.c new file mode 100644 index 0000000000..77f5b30dd6 --- /dev/null +++ b/coregrind/m_syswrap/syswrap-freebsd.c @@ -0,0 +1,6876 @@ +/*--------------------------------------------------------------------*/ +/*--- FreeBSD-specific syscalls, etc. syswrap-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2008 Nicholas Nethercote + njn@valgrind.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGO_freebsd) + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_vkiscnums.h" +#include "pub_core_threadstate.h" +#include "pub_core_aspacemgr.h" +#include "pub_core_debuginfo.h" // VG_(di_notify_*) +#include "pub_core_transtab.h" // VG_(discard_translations) +#include "pub_core_xarray.h" +#include "pub_core_clientstate.h" +#include "pub_core_debuglog.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcfile.h" +#include "pub_core_libcprint.h" +#include "pub_core_libcproc.h" +#include "pub_core_libcsignal.h" +#include "pub_core_machine.h" +#include "pub_core_mallocfree.h" +#include "pub_core_tooliface.h" +#include "pub_core_options.h" +#include "pub_core_scheduler.h" +#include "pub_core_signals.h" +#include "pub_core_stacks.h" +#include "pub_core_syscall.h" +#include "pub_core_syswrap.h" +#include "pub_core_inner.h" +#if defined(ENABLE_INNER_CLIENT_REQUEST) +#include "pub_core_clreq.h" +#endif + +#include "priv_types_n_macros.h" +#include "priv_syswrap-generic.h" +#include "priv_syswrap-main.h" +#include "priv_syswrap-freebsd.h" + +static Bool capabiltyMode = False; + +Bool VG_(get_capability_mode)(void) +{ + return capabiltyMode; +} + + +// Run a thread from beginning to end and return the thread's +// scheduler-return-code. +static VgSchedReturnCode thread_wrapper(Word /*ThreadId*/ tidW) +{ + VgSchedReturnCode ret; + ThreadId tid = (ThreadId)tidW; + ThreadState* tst = VG_(get_ThreadState)(tid); + + VG_(debugLog)(1, "syswrap-freebsd", + "thread_wrapper(tid=%u): entry\n", + tid); + + vg_assert(tst->status == VgTs_Init); + + /* make sure we get the CPU lock before doing anything significant */ + VG_(acquire_BigLock)(tid, "thread_wrapper(starting new thread)"); + + if (0) + VG_(printf)("thread tid %u started: stack = %p\n", + tid, (void*)&tid); + + /* Make sure error reporting is enabled in the new thread. */ + tst->err_disablement_level = 0; + + VG_TRACK(pre_thread_first_insn, tid); + + tst->os_state.lwpid = VG_(gettid)(); + /* Set the threadgroup for real. This overwrites the provisional value set + in do_clone(). See comments in do_clone for background, also #226116. */ + tst->os_state.threadgroup = VG_(getpid)(); + + /* Thread created with all signals blocked; scheduler will set the + appropriate mask */ + + ret = VG_(scheduler)(tid); + + vg_assert(VG_(is_exiting)(tid)); + + vg_assert(tst->status == VgTs_Runnable); + vg_assert(VG_(is_running_thread)(tid)); + + VG_(debugLog)(1, "syswrap-freebsd", + "thread_wrapper(tid=%u): exit, schedreturncode %s\n", + tid, VG_(name_of_VgSchedReturnCode)(ret)); + + /* Return to caller, still holding the lock. */ + return ret; +} + + +/* --------------------------------------------------------------------- + clone-related stuff + ------------------------------------------------------------------ */ + +/* Run a thread all the way to the end, then do appropriate exit actions + (this is the last-one-out-turn-off-the-lights bit). */ +__attribute__((noreturn)) +static void run_a_thread_NORETURN ( Word tidW ) +{ + ThreadId tid = (ThreadId)tidW; + VgSchedReturnCode src; + Int c; + ThreadState* tst; +#ifdef ENABLE_INNER_CLIENT_REQUEST + Int registered_vgstack_id; +#endif + + VG_(debugLog)(1, "syswrap-freebsd", + "run_a_thread_NORETURN(tid=%u): pre-thread_wrapper\n", + tid); + + tst = VG_(get_ThreadState)(tid); + vg_assert(tst); + + /* An thread has two stacks: + * the simulated stack (used by the synthetic cpu. Guest process + is using this stack). + * the valgrind stack (used by the real cpu. Valgrind code is running + on this stack). + When Valgrind runs as an inner, it must signals that its (real) stack + is the stack to use by the outer to e.g. do stacktraces. + */ + INNER_REQUEST + (registered_vgstack_id + = VALGRIND_STACK_REGISTER (tst->os_state.valgrind_stack_base, + tst->os_state.valgrind_stack_init_SP)); + + /* Run the thread all the way through. */ + src = thread_wrapper(tid); + + VG_(debugLog)(1, "syswrap-freebsd", + "run_a_thread_NORETURN(tid=%u): post-thread_wrapper\n", + tid); + + c = VG_(count_living_threads)(); + vg_assert(c >= 1); /* stay sane */ + + /* Deregister thread's stack. */ + if (tst->os_state.stk_id != NULL_STK_ID) + VG_(deregister_stack)(tst->os_state.stk_id); + + // Tell the tool this thread is exiting + VG_TRACK( pre_thread_ll_exit, tid ); + + /* If the thread is exiting with errors disabled, complain loudly; + doing so is bad (does the user know this has happened?) Also, + in all cases, be paranoid and clear the flag anyway so that the + thread slot is safe in this respect if later reallocated. This + should be unnecessary since the flag should be cleared when the + slot is reallocated, in thread_wrapper(). */ + if (tst->err_disablement_level > 0) { + VG_(umsg)( + "WARNING: exiting thread has error reporting disabled.\n" + "WARNING: possibly as a result of some mistake in the use\n" + "WARNING: of the VALGRIND_DISABLE_ERROR_REPORTING macros.\n" + ); + VG_(debugLog)( + 1, "syswrap-freebsd", + "run_a_thread_NORETURN(tid=%u): " + "WARNING: exiting thread has err_disablement_level = %u\n", + tid, tst->err_disablement_level + ); + } + tst->err_disablement_level = 0; + + if (c == 1) { + + VG_(debugLog)(1, "syswrap-freebsd", + "run_a_thread_NORETURN(tid=%u): " + "last one standing\n", + tid); + + /* We are the last one standing. Keep hold of the lock and + carry on to show final tool results, then exit the entire system. + Use the continuation pointer set at startup in m_main. */ + ( * VG_(address_of_m_main_shutdown_actions_NORETURN) ) (tid, src); + } else { + + VG_(debugLog)(1, "syswrap-freebsd", + "run_a_thread_NORETURN(tid=%u): " + "not last one standing\n", + tid); + + /* OK, thread is dead, but others still exist. Just exit. */ + + /* This releases the run lock */ + VG_(exit_thread)(tid); + vg_assert(tst->status == VgTs_Zombie); + vg_assert(sizeof(tst->status) == 4); + vg_assert(sizeof(tst->os_state.exitcode) == sizeof(Word)); + + INNER_REQUEST (VALGRIND_STACK_DEREGISTER (registered_vgstack_id)); + + /* We have to use this sequence to terminate the thread to + prevent a subtle race. If VG_(exit_thread)() had left the + ThreadState as Empty, then it could have been reallocated, + reusing the stack while we're doing these last cleanups. + Instead, VG_(exit_thread) leaves it as Zombie to prevent + reallocation. We need to make sure we don't touch the stack + between marking it Empty and exiting. Hence the + assembler. */ +#if defined(VGP_x86_freebsd) /* FreeBSD has args on the stack */ + asm volatile ( + "movl %1, %0\n" /* set tst->status = VgTs_Empty */ + "movl %2, %%eax\n" /* set %eax = __NR_thr_exit */ + "movl %3, %%ebx\n" /* set %ebx = tst->os_state.exitcode */ + "pushl %%ebx\n" /* arg on stack */ + "pushl %%ebx\n" /* fake return address */ + "int $0x80\n" /* thr_exit(tst->os_state.exitcode) */ + "popl %%ebx\n" /* fake return address */ + "popl %%ebx\n" /* arg off stack */ + : "=m" (tst->status) + : "n" (VgTs_Empty), "n" (__NR_thr_exit), "m" (tst->os_state.exitcode) + : "eax", "ebx" + ); +#elif defined(VGP_amd64_freebsd) + asm volatile ( + "movl %1, %0\n" /* set tst->status = VgTs_Empty */ + "movq %2, %%rax\n" /* set %rax = __NR_thr_exit */ + "movq %3, %%rdi\n" /* set %rdi = tst->os_state.exitcode */ + "pushq %%rdi\n" /* fake return address */ + "syscall\n" /* thr_exit(tst->os_state.exitcode) */ + "popq %%rdi\n" /* fake return address */ + : "=m" (tst->status) + : "n" (VgTs_Empty), "n" (__NR_thr_exit), "m" (tst->os_state.exitcode) + : "rax", "rdi" + ); +#else +# error Unknown platform +#endif + + VG_(core_panic)("Thread exit failed?\n"); + } + + /*NOTREACHED*/ + vg_assert(0); +} + +Word ML_(start_thread_NORETURN) ( void* arg ) +{ + ThreadState* tst = (ThreadState*)arg; + ThreadId tid = tst->tid; + + run_a_thread_NORETURN ( (Word)tid ); + /*NOTREACHED*/ + vg_assert(0); +} + +/* Allocate a stack for this thread, if it doesn't already have one. + They're allocated lazily, and never freed. Returns the initial stack + pointer value to use, or 0 if allocation failed. */ +Addr ML_(allocstack)(ThreadId tid) +{ + ThreadState* tst = VG_(get_ThreadState)(tid); + VgStack* stack; + Addr initial_SP; + + /* Either the stack_base and stack_init_SP are both zero (in which + case a stack hasn't been allocated) or they are both non-zero, + in which case it has. */ + + if (tst->os_state.valgrind_stack_base == 0) + vg_assert(tst->os_state.valgrind_stack_init_SP == 0); + + if (tst->os_state.valgrind_stack_base != 0) + vg_assert(tst->os_state.valgrind_stack_init_SP != 0); + + /* If no stack is present, allocate one. */ + + if (tst->os_state.valgrind_stack_base == 0) { + stack = VG_(am_alloc_VgStack)( &initial_SP ); + if (stack) { + tst->os_state.valgrind_stack_base = (Addr)stack; + tst->os_state.valgrind_stack_init_SP = initial_SP; + } + } + + if (0) + VG_(printf)( "stack for tid %u at %p; init_SP=%p\n", + tid, + (void*)tst->os_state.valgrind_stack_base, + (void*)tst->os_state.valgrind_stack_init_SP ); + + return tst->os_state.valgrind_stack_init_SP; +} + +/* Allocate a stack for the main thread, and run it all the way to the + end. Although we already have a working VgStack + (VG_(interim_stack)) it's better to allocate a new one, so that + overflow detection works uniformly for all threads. +*/ +__attribute__((noreturn)) +void VG_(main_thread_wrapper_NORETURN)(ThreadId tid) +{ + Addr sp; + VG_(debugLog)(1, "syswrap-freebsd", + "entering VG_(main_thread_wrapper_NORETURN)\n"); + + sp = ML_(allocstack)(tid); +#if defined(ENABLE_INNER_CLIENT_REQUEST) + { + // we must register the main thread stack before the call + // to ML_(call_on_new_stack_0_1), otherwise the outer valgrind + // reports 'write error' on the non registered stack. + ThreadState* tst = VG_(get_ThreadState)(tid); + INNER_REQUEST + ((void) + VALGRIND_STACK_REGISTER (tst->os_state.valgrind_stack_base, + tst->os_state.valgrind_stack_init_SP)); + } +#endif + + /* If we can't even allocate the first thread's stack, we're hosed. + Give up. */ + vg_assert2(sp != 0, "%s", "Cannot allocate main thread's stack."); + + /* shouldn't be any other threads around yet */ + vg_assert( VG_(count_living_threads)() == 1 ); + + ML_(call_on_new_stack_0_1)( + (Addr)sp, /* stack */ + 0, /* bogus return address */ + run_a_thread_NORETURN, /* fn to call */ + (Word)tid /* arg to give it */ + ); + + /*NOTREACHED*/ + vg_assert(0); +} + + +/* Do a fork() */ +SysRes ML_(do_fork) ( ThreadId tid ) +{ + vki_sigset_t fork_saved_mask; + vki_sigset_t mask; + SysRes res; + + /* Block all signals during fork, so that we can fix things up in + the child without being interrupted. */ + VG_(sigfillset)(&mask); + VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, &fork_saved_mask); + + VG_(do_atfork_pre)(tid); + + res = VG_(do_syscall0)( __NR_fork ); + + if (!sr_isError(res)) { + if (sr_Res(res) == 0) { + /* child */ + VG_(do_atfork_child)(tid); + + /* restore signal mask */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL); + + } else { + /* parent */ + VG_(do_atfork_parent)(tid); + + if (VG_(clo_trace_syscalls)) + VG_(printf)(" clone(fork): process %d created child %lu\n", + VG_(getpid)(), sr_Res(res)); + + /* restore signal mask */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL); + } + } + + return res; +} + +static Addr ML_(make_safe_mask) ( const HChar* malloc_message, Addr mask_pointer ) +{ + vki_sigset_t* new_mask; + const vki_sigset_t* old_mask = (vki_sigset_t *)mask_pointer; + + if (!ML_(safe_to_deref)(old_mask, sizeof(vki_sigset_t))) { + new_mask = (vki_sigset_t*)1; /* Something recognisable to POST() hook. */ + } else { + new_mask = VG_(malloc)(malloc_message, sizeof(vki_sigset_t)); + *new_mask = *old_mask; + VG_(sanitize_client_sigmask)(new_mask); + } + + return (Addr)new_mask; +} + +static void ML_(free_safe_mask) ( Addr mask_pointer ) +{ + if (mask_pointer != 0 && mask_pointer != 1) { + VG_(free)((vki_sigset_t *) mask_pointer); + } +} + + +/* --------------------------------------------------------------------- + PRE/POST wrappers for arch-generic, FreeBSD-specific syscalls + ------------------------------------------------------------------ */ + +// Nb: See the comment above the generic PRE/POST wrappers in +// m_syswrap/syswrap-generic.c for notes about how they work. + +#define PRE(name) DEFN_PRE_TEMPLATE(freebsd, name) +#define POST(name) DEFN_POST_TEMPLATE(freebsd, name) + +/* On FreeBSD, if any thread calls exit(2), then they are all shut down, pretty + * much like linux's exit_group(). + */ +// SYS_exit 1 +// void exit(int status); +PRE(sys_exit) +{ + ThreadId t; + + PRINT("exit( %" FMT_REGWORD "u )", ARG1); + PRE_REG_READ1(void, "exit", int, status); + + /* Mark all threads (including this one) to exit. */ + for (t = 1; t < VG_N_THREADS; t++) { + if ( /* not alive */ VG_(threads)[t].status == VgTs_Empty ) + continue; + + //VG_(threads)[t].exitreason = VgSrc_ExitThread; + VG_(threads)[t].os_state.exitcode = ARG1; + + // if (t != tid) + // VG_(get_thread_out_of_syscall)(t); /* unblock it, if blocked */ + } + + VG_(nuke_all_threads_except)( tid, VgSrc_ExitProcess ); + VG_(reap_threads)(tid); + VG_(threads)[tid].exitreason = VgSrc_ExitThread; + + /* We have to claim the syscall already succeeded. */ + SET_STATUS_Success(0); +} + +// SYS_fork 2 +// pid_t fork(void); +PRE(sys_fork) +{ + PRINT("%s", "sys_fork ()"); + PRE_REG_READ0(pid_t, "fork"); + + SET_STATUS_from_SysRes( ML_(do_fork)(tid) ); + if (SUCCESS) { + /* Thread creation was successful; let the child have the chance + to run */ + *flags |= SfYieldAfter; + } +} + +// SYS_read 3 +// generic + +// SYS_write 4 +// generic + +// SYS_open 5 +// generic + +// SYS_close 6 +// generic + +// SYS_wait4 7 +// generic + +// SYS_link 9 +// generic + +// SYS_unlink 10 +// generic + +// SYS_chdir 12 + +// SYS_fchdir 13 +// generic + +// SYS_freebsd11_mknod 14 +// generic + +// SYS_chmod 15 +// generic + +// SYS_chown 16 +// generic + +// SYS_break 17 +// generic + +// SYS_getpid 20 +// generic + +// SYS_mount 21 +// int mount(const char *type, const char *dir, int flags, void *data); +PRE(sys_mount) +{ + // Nb: depending on 'flags', the 'type' and 'data' args may be ignored. + // We are conservative and check everything, except the memory pointed to + // by 'data'. + *flags |= SfMayBlock; + PRINT( "sys_mount( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "mount", + const char *, type, char *, dir, int, flags, + void *, data); + PRE_MEM_RASCIIZ( "mount(type)", ARG1); + PRE_MEM_RASCIIZ( "mount(path)", ARG2); +} + +// SYS_unmount 22 +// int unmount(const char *dir, int flags); +PRE(sys_unmount) +{ + PRINT("sys_umount( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2); + PRE_REG_READ2(int, "unmount", const char *, dir, int, flags); + PRE_MEM_RASCIIZ( "unmount(path)", ARG1); +} + +// SYS_setuid 23 +// generic + +// SYS_getuid 24 +// generic + +// SYS_geteuid 25 +// generic + +// SYS_ptrace 26 +// int ptrace(int request, pid_t pid, caddr_t addr, int data); +PRE(sys_ptrace) +{ + struct vki_ptrace_io_desc *io_desc; + PRINT("sys_ptrace ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, %" FMT_REGWORD "u)", ARG1, ARG2, ARG3, ARG4); + + PRE_REG_READ4(int, "ptrace", int, request, pid_t, pid, caddr_t, addr, int, data); + + switch (ARG1) { + case VKI_PTRACE_TRACEME: + break; + case VKI_PTRACE_READ_I: + case VKI_PTRACE_READ_D: + break; + + case VKI_PTRACE_WRITE_I: + case VKI_PTRACE_WRITE_D: + break; + + case VKI_PTRACE_IO: + PRE_MEM_READ("ptrace", ARG3, sizeof(struct vki_ptrace_io_desc)); + io_desc = (struct vki_ptrace_io_desc *)ARG3; + switch (io_desc->piod_op) { + case VKI_PIOD_READ_D: + case VKI_PIOD_READ_I: + PRE_MEM_WRITE( "ptrace", (UWord)io_desc->piod_addr, io_desc->piod_len); + break; + case VKI_PIOD_WRITE_D: + case VKI_PIOD_WRITE_I: + PRE_MEM_READ( "ptrace", (UWord)io_desc->piod_addr, io_desc->piod_len); + break; + } + break; + + case VKI_PTRACE_CONTINUE: + break; + + case VKI_PTRACE_STEP: + break; + + case VKI_PTRACE_KILL: + break; + + case VKI_PTRACE_ATTACH: + break; + + case VKI_PTRACE_DETACH: + break; + + case VKI_PTRACE_GETREGS: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(struct vki_user_regs_struct)); + break; + + case VKI_PTRACE_SETREGS: + PRE_MEM_READ( "ptrace", ARG3, sizeof(struct vki_user_regs_struct)); + break; + + case VKI_PTRACE_GETFPREGS: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(struct vki_fpreg)); + break; + + case VKI_PTRACE_SETFPREGS: + PRE_MEM_READ( "ptrace", ARG3, sizeof(struct vki_fpreg)); + break; + + case VKI_PTRACE_GETDBREGS: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(struct vki_dbreg)); + break; + + case VKI_PTRACE_SETDBREGS: + PRE_MEM_READ( "ptrace", ARG3, sizeof(struct vki_dbreg)); + break; + + case VKI_PTRACE_LWPINFO: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(struct vki_ptrace_lwpinfo)); + break; + + case VKI_PTRACE_GETNUMLWPS: + break; + + case VKI_PTRACE_GETLWPLIST: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(vki_lwpid_t) * ARG4); + break; + + case VKI_PTRACE_SETSTEP: + break; + + case VKI_PTRACE_CLEARSTEP: + break; + + case VKI_PTRACE_SUSPEND: + break; + + case VKI_PTRACE_RESUME: + break; + + case VKI_PTRACE_TO_SCE: + break; + + case VKI_PTRACE_TO_SCX: + break; + + case VKI_PTRACE_SYSCALL: + break; + + case VKI_PTRACE_VM_TIMESTAMP: + break; + + case VKI_PTRACE_VM_ENTRY: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(struct vki_ptrace_vm_entry)); + break; + } +} + +POST(sys_ptrace) +{ + struct vki_ptrace_io_desc *io_desc; + + switch (ARG1) { + case VKI_PTRACE_TRACEME: + break; + case VKI_PTRACE_READ_I: + case VKI_PTRACE_READ_D: + break; + + case VKI_PTRACE_WRITE_I: + case VKI_PTRACE_WRITE_D: + break; + + case VKI_PTRACE_IO: + io_desc = (struct vki_ptrace_io_desc *)ARG3; + switch (io_desc->piod_op) { + case VKI_PIOD_READ_D: + case VKI_PIOD_READ_I: + if ((Word)RES != -1) + POST_MEM_WRITE((UWord)io_desc->piod_addr, io_desc->piod_len); + break; + case VKI_PIOD_WRITE_D: + case VKI_PIOD_WRITE_I: + break; + } + break; + + case VKI_PTRACE_CONTINUE: + break; + + case VKI_PTRACE_STEP: + break; + + case VKI_PTRACE_KILL: + break; + + case VKI_PTRACE_ATTACH: + break; + + case VKI_PTRACE_DETACH: + break; + + case VKI_PTRACE_GETREGS: + if ((Word)RES != -1) + POST_MEM_WRITE(ARG3, sizeof(struct vki_user_regs_struct)); + break; + + case VKI_PTRACE_SETREGS: + break; + + case VKI_PTRACE_GETFPREGS: + if ((Word)RES != -1) + POST_MEM_WRITE(ARG3, sizeof(struct vki_fpreg)); + break; + + case VKI_PTRACE_SETFPREGS: + break; + + case VKI_PTRACE_GETDBREGS: + if ((Word)RES != -1) + POST_MEM_WRITE(ARG3, sizeof(struct vki_dbreg)); + break; + + case VKI_PTRACE_SETDBREGS: + break; + + case VKI_PTRACE_LWPINFO: + if ((Word)RES != -1) + POST_MEM_WRITE(ARG3, sizeof(struct vki_ptrace_lwpinfo)); + break; + + case VKI_PTRACE_GETNUMLWPS: + break; + + case VKI_PTRACE_GETLWPLIST: + if ((Word)RES != -1) + POST_MEM_WRITE(ARG3, sizeof(vki_lwpid_t) * RES); + break; + + case VKI_PTRACE_SETSTEP: + break; + + case VKI_PTRACE_CLEARSTEP: + break; + + case VKI_PTRACE_SUSPEND: + break; + + case VKI_PTRACE_RESUME: + break; + + case VKI_PTRACE_TO_SCE: + break; + + case VKI_PTRACE_TO_SCX: + break; + + case VKI_PTRACE_SYSCALL: + break; + + case VKI_PTRACE_VM_TIMESTAMP: + break; + + case VKI_PTRACE_VM_ENTRY: + if ((Word)RES != -1) + POST_MEM_WRITE(ARG3, sizeof(struct vki_ptrace_vm_entry)); + break; + } +} + +// SYS_recvmsg 27 +// ssize_t recvmsg(int s, struct msghdr *msg, int flags); +PRE(sys_recvmsg) +{ + *flags |= SfMayBlock; + PRINT("sys_recvmsg ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",SARG1,ARG2,SARG3); + PRE_REG_READ3(vki_ssize_t, "recvmsg", int, s, struct msghdr *, msg, int, flags); + ML_(generic_PRE_sys_recvmsg)(tid, "recvmsg", (struct vki_msghdr *)ARG2); +} + +POST(sys_recvmsg) +{ + + ML_(generic_POST_sys_recvmsg)(tid, "recvmsg", (struct vki_msghdr *)ARG2, RES); +} + +// SYS_sendmsg 28 +// ssize_t sendmsg(int s, const struct msghdr *msg, int flags); +PRE(sys_sendmsg) +{ + *flags |= SfMayBlock; + PRINT("sys_sendmsg ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(ssize_t, "sendmsg", + int, s, const struct msghdr *, msg, int, flags); + ML_(generic_PRE_sys_sendmsg)(tid, "sendmsg", (struct vki_msghdr *)ARG2); +} + +// SYS_recvfrom 29 +// ssize_t recvfrom(int s, void *buf, size_t len, int flags, +// struct sockaddr * restrict from, socklen_t * restrict fromlen); +PRE(sys_recvfrom) +{ + *flags |= SfMayBlock; + PRINT("sys_recvfrom ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",SARG1,ARG2,ARG3,SARG4,ARG5,ARG6); + PRE_REG_READ6(ssize_t, "recvfrom", + int, s, void *, buf, size_t, len, int, flags, + struct sockaddr *, from, int *, fromlen); + ML_(generic_PRE_sys_recvfrom)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6); +} + +POST(sys_recvfrom) +{ + vg_assert(SUCCESS); + ML_(generic_POST_sys_recvfrom)(tid, VG_(mk_SysRes_Success)(RES), + ARG1,ARG2,ARG3,ARG4,ARG5,ARG6); +} + +// SYS_accept 30 +// int accept(int s, struct sockaddr * restrict addr, +// socklen_t * restrict addrlen); +PRE(sys_accept) +{ + *flags |= SfMayBlock; + PRINT("sys_accept ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "accept", + int, s, struct sockaddr *, addr, int, *addrlen); + ML_(generic_PRE_sys_accept)(tid, ARG1,ARG2,ARG3); +} + +POST(sys_accept) +{ + SysRes r; + vg_assert(SUCCESS); + r = ML_(generic_POST_sys_accept)(tid, VG_(mk_SysRes_Success)(RES), + ARG1,ARG2,ARG3); + SET_STATUS_from_SysRes(r); +} + +// SYS_getpeername 31 +// int getpeername(int s, struct sockaddr * restrict name, +// socklen_t * restrict namelen); +PRE(sys_getpeername) +{ + PRINT("sys_getpeername ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "getpeername", + int, s, struct sockaddr *, name, socklen_t *, namelen); + ML_(generic_PRE_sys_getpeername)(tid, ARG1,ARG2,ARG3); +} + +POST(sys_getpeername) +{ + vg_assert(SUCCESS); + ML_(generic_POST_sys_getpeername)(tid, VG_(mk_SysRes_Success)(RES), + ARG1,ARG2,ARG3); +} + +// SYS_getsockname 32 +// int getsockname(int s, struct sockaddr * restrict name, +// socklen_t * restrict namelen); +PRE(sys_getsockname) +{ + PRINT("sys_getsockname ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",SARG1,ARG2,ARG3); + PRE_REG_READ3(long, "getsockname", + int, s, struct sockaddr *, name, int *, namelen); + ML_(generic_PRE_sys_getsockname)(tid, ARG1,ARG2,ARG3); +} + +POST(sys_getsockname) +{ + vg_assert(SUCCESS); + ML_(generic_POST_sys_getsockname)(tid, VG_(mk_SysRes_Success)(RES), + ARG1,ARG2,ARG3); +} + +// SYS_access 33 +// generic + +// SYS_chflags 34 +// int fchflags(int fd, unsigned long flags) +PRE(sys_chflags) +{ + PRINT("sys_chflags ( %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "chflags", + const char *, path, unsigned long, flags); + PRE_MEM_RASCIIZ( "chflags(path)", ARG1 ); +} + +// SYS_fchflags 35 +// int fchflags(int fd, unsigned long flags); +PRE(sys_fchflags) +{ + PRINT("sys_fchflags ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG2); + PRE_REG_READ2(int, "fchflags", int, fd, unsigned long, flags); +} + +// SYS_sync 36 +// generic + +// SYS_kill 37 +// generic + +// SYS_getppid 39 +// generic + +// SYS_dup 41 +// generic + +// Pipe on freebsd doesn't have args, and uses dual returns! +// SYS_freebsd10_pipe 42 +// int pipe(void); +PRE(sys_pipe) +{ + PRINT("%s", "sys_pipe ()"); +} + +POST(sys_pipe) +{ + if (!ML_(fd_allowed)(RES, "pipe", tid, True) || + !ML_(fd_allowed)(RESHI, "pipe", tid, True)) { + VG_(close)(RES); + VG_(close)(RESHI); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) { + ML_(record_fd_open_nameless)(tid, RES); + ML_(record_fd_open_nameless)(tid, RESHI); + } + } +} + +// SYS_getegid 43 +// generic + +// SYS_profil 44 +// generic + +// SYS_ktrace 45 +// generic + +// SYS_getgid 47 +// generic + +// SYS_getlogin 49 +// syscall.master refers to namelen and namebuf for the argument names +// man getlogin has just getlogin(void) but also +// int getlogin_r(char *name, int len); +// so let's go with those names +PRE(sys_getlogin) +{ + PRINT("sys_getlogin ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2); + PRE_REG_READ2(int, "getlogin", char *, buf, u_int, len); + PRE_MEM_WRITE( "getlogin(name)", ARG1, ARG2 ); +} + +POST(sys_getlogin) +{ + POST_MEM_WRITE(ARG1, ARG2 ); +} + +// SYS_setlogin 50 +// int setlogin(const char *name); +PRE(sys_setlogin) +{ + PRINT("sys_setlogin ( %#" FMT_REGWORD "x )",ARG1); + PRE_REG_READ1(long, "setlogin", char *, buf); + PRE_MEM_RASCIIZ( "setlogin(buf)", ARG1 ); +} + +// SYS_acct 51 +// generic + +// SYS_sigaltstack 53 +// generic + +// SYS_ioctl 54 +// int ioctl(int fd, unsigned long request, ...); +PRE(sys_ioctl) +{ + UInt dir = _VKI_IOC_DIR(ARG2); + UInt size = _VKI_IOC_SIZE(ARG2); + *flags |= SfMayBlock; + // @todo PJF presumably the presence of ARG3 depends on ARG2 + PRINT("sys_ioctl ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "ioctl", + int, fd, unsigned long, request, unsigned long, arg); + + /* On FreeBSD, ALL ioctl's are IOR/IOW encoded. Just use the default decoder */ + if (SimHintiS(SimHint_lax_ioctls, VG_(clo_sim_hints))) { + /* + * Be very lax about ioctl handling; the only + * assumption is that the size is correct. Doesn't + * require the full buffer to be initialized when + * writing. Without this, using some device + * drivers with a large number of strange ioctl + * commands becomes very tiresome. + */ + } else if ((dir == _VKI_IOC_NONE) && size > 0) { + static UWord unknown_ioctl[10]; + static Int moans = sizeof(unknown_ioctl) / sizeof(unknown_ioctl[0]); + if (moans > 0 && !VG_(clo_xml)) { + /* Check if have not already moaned for this request. */ + UInt i; + for (i = 0; i < sizeof(unknown_ioctl)/sizeof(unknown_ioctl[0]); i++) { + if (unknown_ioctl[i] == ARG2) + break; + if (unknown_ioctl[i] == 0) { + unknown_ioctl[i] = ARG2; + moans--; + VG_(umsg)("Warning: noted but unhandled ioctl 0x%lx" + " with no size/direction hints.\n", ARG2); + VG_(umsg)(" This could cause spurious value errors to appear.\n"); + VG_(umsg)(" See README_MISSING_SYSCALL_OR_IOCTL for " + "guidance on writing a proper wrapper.\n" ); + //VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size)); + return; + } + } + } + } else { + if ((dir & _VKI_IOC_WRITE) && size > 0) + PRE_MEM_READ( "ioctl(generic)", ARG3, size); + if ((dir & _VKI_IOC_READ) && size > 0) + PRE_MEM_WRITE( "ioctl(generic)", ARG3, size); + } + + // The block below is from Ryan Stone + // https://bitbucket.org/rysto32/valgrind-freebsd/commits/5323c22be9f6c71a00e842c3ddfa1fa8a7feb279 + // however it drags in hundreds of lines of headers into vki-freebsd.h. + // How stable are these structures? -> maintainability is a concern + // Also there are no testcases for this. + // Hence #if 0 +#if 0 + /* Handle specific ioctls which pass structures which may have pointers to other + buffers */ + switch (ARG2 /* request */) { + case VKI_SIOCGIFMEDIA: + if (ARG3) { + struct vki_ifmediareq* imr = (struct vki_ifmediareq*)ARG3; + if (imr->ifm_ulist) { + PRE_MEM_WRITE("ioctl(SIOCGIFMEDIA).ifm_ulist", + (Addr)(imr->ifm_ulist), imr->ifm_count * sizeof(int)); + } + } + break; + + case VKI_PCIOCGETCONF: + if (ARG3) { + struct vki_pci_conf_io* pci = (struct vki_pci_conf_io*)ARG3; + PRE_MEM_READ("ioctl(PCIOCGETCONF).patterns", + (Addr)(pci->patterns), pci->pat_buf_len); + PRE_MEM_WRITE("ioctl(PCIOCGETCONF).matches", + (Addr)(pci->matches), pci->match_buf_len); + } + break; + + case VKI_CAMIOCOMMAND: + if (ARG3) { + union vki_ccb* ccb = (union vki_ccb*)ARG3; + if (ccb->ccb_h.func_code == VKI_XPT_DEV_MATCH) { + PRE_MEM_WRITE("ioctl(CAMIOCOMMAND:XPT_DEV_MATCH).matches", + (Addr)(ccb->cdm.matches), ccb->cdm.match_buf_len); + } else if (ccb->ccb_h.func_code == VKI_XPT_SCSI_IO) { + struct vki_ccb_scsiio* scsiio = (struct vki_ccb_scsiio*)ccb; + if (scsiio->dxfer_len) { + if ((scsiio->ccb_h.flags & VKI_CAM_DIR_MASK) == VKI_CAM_DIR_IN) { + PRE_MEM_WRITE("ioctl(CAMIOCOMMAND:XPT_SCSI_IO).data_ptr", + (Addr)(scsiio->data_ptr), scsiio->dxfer_len); + } else if ((scsiio->ccb_h.flags & VKI_CAM_DIR_MASK) == VKI_CAM_DIR_OUT) { + PRE_MEM_READ("ioctl(CAMIOCOMMAND:XPT_SCSI_IO).data_ptr", + (Addr)(scsiio->data_ptr), scsiio->dxfer_len); + } + } + } else if (ccb->ccb_h.func_code == VKI_XPT_GDEV_TYPE || + ccb->ccb_h.func_code == VKI_XPT_PATH_INQ || + ccb->ccb_h.func_code == VKI_XPT_GET_TRAN_SETTINGS) { + // do nothing + } else { + VG_(message)(Vg_UserMsg, + "Warning: unhandled ioctl CAMIOCOMMAND function 0x%lx\n", + ccb->ccb_h.func_code); + } + } + break; + } +#endif +} + +POST(sys_ioctl) +{ + UInt dir = _VKI_IOC_DIR(ARG2); + UInt size = _VKI_IOC_SIZE(ARG2); + vg_assert(SUCCESS); + if (size > 0 && (dir & _VKI_IOC_READ) + && RES == 0 && ARG3 != (Addr)NULL) + POST_MEM_WRITE(ARG3, size); + +#if 0 + /* Handle specific ioctls which pass structures which may have pointers to other + buffers */ + switch (ARG2 /* request */) { + case VKI_SIOCGIFMEDIA: + if (ARG3) { + struct vki_ifmediareq* imr = (struct vki_ifmediareq*)ARG3; + if (imr->ifm_ulist) { + POST_MEM_WRITE((Addr)(imr->ifm_ulist), imr->ifm_count * sizeof(int)); + } + } + break; + + case VKI_PCIOCGETCONF: + if (ARG3) { + struct vki_pci_conf_io* pci = (struct vki_pci_conf_io*)ARG3; + POST_MEM_WRITE((Addr)(pci->matches), pci->num_matches * sizeof(struct vki_pci_conf)); + } + break; + + case VKI_CAMIOCOMMAND: + if (ARG3) { + union vki_ccb* ccb = (union vki_ccb*)ARG3; + if (ccb->ccb_h.func_code == VKI_XPT_DEV_MATCH) { + POST_MEM_WRITE((Addr)(ccb->cdm.matches), ccb->cdm.num_matches*sizeof(struct vki_dev_match_result)); + } else if (ccb->ccb_h.func_code == VKI_XPT_SCSI_IO) { + struct vki_ccb_scsiio* scsiio = (struct vki_ccb_scsiio*)ccb; + if (scsiio->dxfer_len) { + if ((scsiio->ccb_h.flags & VKI_CAM_DIR_MASK) == VKI_CAM_DIR_IN) { + POST_MEM_WRITE((Addr)(scsiio->data_ptr), scsiio->dxfer_len); + } + } + } + } + break; + } +#endif +} + +// SYS_reboot 55 +// int reboot(int howto); +PRE(sys_reboot) +{ + PRINT("sys_reboot ( %" FMT_REGWORD "d )", SARG1); + PRE_REG_READ1(int, "reboot", int, howto); +} + +// SYS_revoke 56 +// int revoke(const char *path); +PRE(sys_revoke) +{ + PRINT("sys_revoke ( %#" FMT_REGWORD "x(%s) )", ARG1, (char*)ARG1); + PRE_REG_READ1(long, "revoke", const char *, path); + PRE_MEM_RASCIIZ( "revoke(path)", ARG1); +} + +// SYS_symlink 57 +// generic + +// SYS_readlink 58 +// generic + +// SYS_execve 59 +// generic + +// SYS_umask 60 +// generic + +// SYS_chroot 61 +// generic + +// SYS_msync 65 +// generic + +// SYS_vfork 66 +// pid_t vfork(void); +PRE(sys_vfork) +{ + PRINT("%s", "sys_vfork ()"); + PRE_REG_READ0(pid_t, "vfork"); + + /* Pretend vfork == fork. Not true, but will have to do. */ + SET_STATUS_from_SysRes( ML_(do_fork)(tid) ); + if (SUCCESS) { + /* Thread creation was successful; let the child have the chance + to run */ + *flags |= SfYieldAfter; + } +} + +// SYS_sbrk 69 +// void * sbrk(intptr_t incr); +PRE(sys_sbrk) +{ + PRINT("sys_sbrk ( %#" FMT_REGWORD "x )",ARG1); + PRE_REG_READ1(void*, "sbrk", vki_intptr_t, incr); +} + +// SYS_freebsd11_vadvise 72 +// @todo maybe + +// SYS_munmap 73 +// generic + +// SYS_mprotect 74 +// generic + +// SYS_madvise 75 +// generic + +// SYS_mincore 78 +// generic + +// SYS_getgroups 79 +// generic + +// SYS_setgroups 80 +// generic + +// SYS_getpgrp 81 +// generic + +// SYS_setpgid 82 +// generic + +// SYS_setitimer 83 +// generic + +// SYS_swapon 85 +// int swapon(const char *special); +PRE(sys_swapon) +{ + PRINT("sys_swapon ( %#" FMT_REGWORD "x(%s) )", ARG1,(char*)ARG1); + PRE_REG_READ1(int, "swapon", const char*, special ); + PRE_MEM_RASCIIZ( "swapon(special)", ARG1 ); +} + +// SYS_getitimer 86 +// generic + +// SYS_getdtablesize 89 +// int getdtablesize(void); +PRE(sys_getdtablesize) +{ + PRINT("%s", "sys_getdtablesize ( )"); + PRE_REG_READ0(long, "getdtablesize"); +} + +// SYS_dup2 90 +// generic + +// SYS_fcntl 92 +// int fcntl(int fd, int cmd, ...); +PRE(sys_fcntl) +{ + switch (ARG2) { + // These ones ignore ARG3. + case VKI_F_GETFD: + case VKI_F_GETFL: + case VKI_F_GETOWN: + case VKI_F_GET_SEALS: + case VKI_F_ISUNIONSTACK: + PRINT("sys_fcntl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1,SARG2); + PRE_REG_READ2(int, "fcntl", int, fd, int, cmd); + break; + + // These ones use ARG3 as "arg". + case VKI_F_DUPFD: + case VKI_F_DUPFD_CLOEXEC: + case VKI_F_SETFD: + case VKI_F_SETFL: + case VKI_F_SETOWN: + case VKI_F_READAHEAD: + case VKI_F_RDAHEAD: + case VKI_F_ADD_SEALS: + PRINT("sys_fcntl[ARG3=='arg'] ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1,SARG2,SARG3); + PRE_REG_READ3(int, "fcntl", + int, fd, int, cmd, int, arg); + break; + + // These ones use ARG3 as "lock" - obsolete. + case VKI_F_OSETLKW: + *flags |= SfMayBlock; + /* FALLTHROUGH */ + case VKI_F_OGETLK: + case VKI_F_OSETLK: + PRINT("sys_fcntl[ARG3=='lock'] ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "fcntl", + int, fd, int, cmd, + struct oflock *, lock); + break; + + // This one uses ARG3 as "oldd" and ARG4 as "newd". + case VKI_F_DUP2FD: + case VKI_F_DUP2FD_CLOEXEC: + PRINT("sys_fcntl[ARG3=='oldd', ARG4=='newd'] ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", + ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "fcntl", + int, fd, int, cmd, + unsigned long, oldd, unsigned long, newd); + break; + + // These ones use ARG3 as "lock". + case VKI_F_SETLKW: + *flags |= SfMayBlock; + /* FALLTHROUGH */ + case VKI_F_GETLK: + case VKI_F_SETLK: + case VKI_F_SETLK_REMOTE: + PRINT("sys_fcntl[ARG3=='lock'] ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "fcntl", + int, fd, int, cmd, + struct flock *, lock); + break; + + default: + PRINT("sys_fcntl[UNKNOWN] ( %lu, %lu, %lu )", ARG1,ARG2,ARG3); + I_die_here; + } +} + +POST(sys_fcntl) +{ + vg_assert(SUCCESS); + if (ARG2 == VKI_F_DUPFD) { + if (!ML_(fd_allowed)(RES, "fcntl(DUPFD)", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_named)(tid, RES); + } + } else if (ARG2 == VKI_F_DUPFD_CLOEXEC) { + if (!ML_(fd_allowed)(RES, "fcntl(DUPFD_CLOEXEC)", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_named)(tid, RES); + } + } +} + +// SYS_select 93 +// generic + +// SYS_fsync 95 +// generic + +// SYS_setpriority 9 +// generic + +// SYS_socket 97 +// int socket(int domain, int type, int protocol); +PRE(sys_socket) +{ + PRINT("sys_socket ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d )",SARG1,SARG2,SARG3); + PRE_REG_READ3(int, "socket", int, domain, int, type, int, protocol); +} + +POST(sys_socket) +{ + SysRes r; + vg_assert(SUCCESS); + r = ML_(generic_POST_sys_socket)(tid, VG_(mk_SysRes_Success)(RES)); + SET_STATUS_from_SysRes(r); +} + +// SYS_connect 98 +// int connect(int s, const struct sockaddr *name, socklen_t namelen); +PRE(sys_connect) +{ + *flags |= SfMayBlock; + PRINT("sys_connect ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "connect", + int, s, const struct sockaddr *, name, int, namelen); + ML_(generic_PRE_sys_connect)(tid, ARG1,ARG2,ARG3); +} + +// SYS_getpriority 100 +// generic + +// SYS_bind 104 +// int bind(int s, const struct sockaddr *addr, socklen_t addrlen); +PRE(sys_bind) +{ + PRINT("sys_bind ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "bind", + int, s, struct sockaddr *, addr, int, addrlen); + ML_(generic_PRE_sys_bind)(tid, ARG1,ARG2,ARG3); +} + +// SYS_setsockopt 105 +// int setsockopt(int s, int level, int optname, const void *optval, +// socklen_t optlen); +PRE(sys_setsockopt) +{ + PRINT("sys_setsockopt ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",SARG1,SARG2,SARG3,ARG4,ARG5); + PRE_REG_READ5(int, "setsockopt", + int, s, int, level, int, optname, + const void *, optval, vki_socklen_t, optlen); + ML_(generic_PRE_sys_setsockopt)(tid, ARG1,ARG2,ARG3,ARG4,ARG5); +} + +// SYS_listen 106 +// int listen(int s, int backlog); +PRE(sys_listen) +{ + PRINT("sys_listen ( %" FMT_REGWORD "d, %" FMT_REGWORD "d )",SARG1,SARG2); + PRE_REG_READ2(int, "listen", int, s, int, backlog); +} + +//SYS_gettimeofday 116 +// generic + +// SYS_getrusage 117 +// generic + +// SYS_getsockopt 118 +// int getsockopt(int s, int level, int optname, void * restrict optval, +// socklen_t * restrict optlen); +PRE(sys_getsockopt) +{ + Addr optval_p = ARG4; + Addr optlen_p = ARG5; + PRINT("sys_getsockopt ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4,ARG5); + PRE_REG_READ5(int, "getsockopt", + int, s, int, level, int, optname, + void *, optval, int, *optlen); + if (optval_p != (Addr)NULL) { + ML_(buf_and_len_pre_check) ( tid, optval_p, optlen_p, + "getsockopt(optval)", + "getsockopt(optlen)" ); + } +} + +POST(sys_getsockopt) +{ + Addr optval_p = ARG4; + Addr optlen_p = ARG5; + vg_assert(SUCCESS); + if (optval_p != (Addr)NULL) { + ML_(buf_and_len_post_check) ( tid, VG_(mk_SysRes_Success)(RES), + optval_p, optlen_p, + "getsockopt(optlen_out)" ); + } +} + +// SYS_readv 120 +// generic + +// SYS_writev 121 +// generic + +// SYS_settimeofday 122 +// generic + +// SYS_fchown 123 +// generic + +// SYS_fchmod 124 +// generic + +// SYS_setreuid 126 +// generic + +// SYS_setregid 127 +// generic + +// SYS_rename 128 +// generic + +// SYS_flock 131 +// generic + +// SYS_mkfifo 132 +// int mkfifo(const char *path, mode_t mode); +PRE(sys_mkfifo) +{ + PRINT("sys_mkfifo ( %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", ARG1, (char *)ARG1, ARG2, ARG3 ); + PRE_REG_READ2(int, "mkfifo", const char *, path, int, mode); + PRE_MEM_RASCIIZ( "mkfifo(path)", ARG1 ); +} + +// SYS_sendto 133 +// ssize_t sendto(int s, const void *msg, size_t len, int flags, +// const struct sockaddr *to, socklen_t tolen); +PRE(sys_sendto) +{ + *flags |= SfMayBlock; + PRINT("sys_sendto ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3,ARG4,ARG5,ARG6); + PRE_REG_READ6(ssize_t, "sendto", + int, s, const void *, msg, int, len, + int, flags, + const struct sockaddr *, to, socklen_t, tolen); + ML_(generic_PRE_sys_sendto)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6); +} + +// SYS_shutdown 134 +// int shutdown(int s, int how); +PRE(sys_shutdown) +{ + *flags |= SfMayBlock; + PRINT("sys_shutdown ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2); + PRE_REG_READ2(int, "shutdown", int, s, int, how); +} + +// SYS_socketpair 135 +// int socketpair(int domain, int type, int protocol, int *sv); +PRE(sys_socketpair) +{ + PRINT("sys_socketpair ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "socketpair", + int, domain, int, type, int, protocol, int *, sv); + ML_(generic_PRE_sys_socketpair)(tid, ARG1,ARG2,ARG3,ARG4); +} + +POST(sys_socketpair) +{ + vg_assert(SUCCESS); + ML_(generic_POST_sys_socketpair)(tid, VG_(mk_SysRes_Success)(RES), + ARG1,ARG2,ARG3,ARG4); +} + +// SYS_mkdir 136 +// generic + +// SYS_rmdir 137 +// generic + +// SYS_utimes 138 +// generic + +// SYS_adjtime 140 +// int adjtime(const struct timeval *delta, struct timeval *olddelta); +PRE(sys_adjtime) +{ + PRINT("sys_adjtime ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2); + PRE_REG_READ2(int, "adjtime", + const struct vki_timeval *, delta, struct vki_timeval *, olddelta); + PRE_MEM_READ("adjtime(delta)", ARG1, sizeof(struct vki_timeval)); + if (ARG2) { + PRE_MEM_WRITE("adjtime(olddelta)", ARG1, sizeof(struct vki_timeval)); + } +} + +POST(sys_adjtime) +{ + if (ARG2) { + POST_MEM_WRITE(ARG1, sizeof(struct vki_timeval)); + } +} + +// SYS_setsid 147 +// generic + +// SYS_quotactl 148 +/* int quotactl(const char *path, int cmd, int id, void *addr); */ +PRE(sys_quotactl) +{ + PRINT("sys_quotactl ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3, ARG4); + switch (ARG2) { + case VKI_Q_QUOTAON: + case VKI_Q_SETQUOTA: + case VKI_Q_SETUSE: + + case VKI_Q_GETQUOTASIZE: + PRE_REG_READ4(int, "quotactl", + const char *, path, int, cmd, int, id, + void *, addr); + PRE_MEM_RASCIIZ( "quotactl(path)", ARG1 ); + break; + case VKI_Q_GETQUOTA: + if (VG_(tdict).track_pre_reg_read) { + \ + PRRSN; + PRA1("quotactl",const char*,path); + PRA2("quotactl",int,cmd); + PRA4("quotactl",void*,addr); + } + break; + case VKI_Q_QUOTAOFF: + case VKI_Q_SYNC: + PRE_REG_READ2(int, "quotactl", + const char *, path, int, cmd); + break; + default: + break; + } +} + +// SYS_nlm_syscall 154 +// syscall.master says ; 154 is initialised by the NLM code, if present. +// @todo + +// SYS_nfssvc 155 +// int nfssvc(int flags, void *argstructp); +// lengthy manpage, at least 3 types of struct that argstructp can point to +// @todo + +// SYS_lgetfh 160 +// int lgetfh(const char *path, fhandle_t *fhp); +PRE(sys_lgetfh) +{ + PRINT("sys_lgetfh ( %#" FMT_REGWORD "x, %" FMT_REGWORD "x ", ARG1, ARG2); + PRE_REG_READ2(int, "lgetfh", const char*, path, vki_fhandle_t*, fhp); + PRE_MEM_RASCIIZ( "lgetfh(path)", ARG1 ); + PRE_MEM_WRITE("lgetfh(fhp)", ARG2, sizeof(vki_fhandle_t)); +} + +POST(sys_lgetfh) +{ + POST_MEM_WRITE(ARG2, sizeof(vki_fhandle_t)); +} + +// SYS_getfh 161 +// int getfh(const char *path, fhandle_t *fhp); +PRE(sys_getfh) +{ + PRINT("sys_getfh ( %#" FMT_REGWORD "x, %" FMT_REGWORD "x ", ARG1, ARG2); + PRE_REG_READ2(int, "getfh", const char*, path, vki_fhandle_t*, fhp); + PRE_MEM_RASCIIZ( "getfh(path)", ARG1 ); + PRE_MEM_WRITE("getfh(fhp)", ARG2, sizeof(vki_fhandle_t)); +} + +POST(sys_getfh) +{ + POST_MEM_WRITE(ARG2, sizeof(vki_fhandle_t)); +} + +#if (FREEBSD_VERS <= FREEBSD_10) +// 162 +// int getdomainname(char *domainname, int len); +PRE(sys_freebsd4_getdomainname) +{ + PRINT("sys_freebsd4_getdomainname ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2); + PRE_REG_READ2(int, "getdomainname", + char *, domainname, int, len); + PRE_MEM_WRITE( "getdomainname(domainname)", ARG1, ARG2 ); +} + +POST(sys_freebsd4_getdomainname) +{ + if (ARG1 != 0) { + POST_MEM_WRITE( ARG1, ARG2 ); + } +} + +// 163 +// int setdomainname(char *domainname, int len); +PRE(sys_freebsd4_setdomainname) +{ + PRINT("sys_freebsd4_setdomainname ( %#" FMT_REGWORD "x )",ARG1); + PRE_REG_READ2(int, "setdomainname", char *, domainname, int, len); + PRE_MEM_RASCIIZ( "setdomainname(domainname)", ARG1 ); +} + +// 164 +// int uname(struct utsname *name); +PRE(sys_freebsd4_uname) +{ + PRINT("sys_freebsd4_uname ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "uname", struct utsname *, name); + PRE_MEM_WRITE( "uname(name)", ARG1, sizeof(struct vki_utsname) ); +} + +POST(sys_freebsd4_uname) +{ + if (ARG1 != 0) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_utsname) ); + } +} +#endif + +// SYS_sysarch 165 +// x86/amd64 + +// SYS_rtprio 166 +PRE(sys_rtprio) +{ + PRINT( "sys_rtprio ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2, ARG3 ); + PRE_REG_READ3(int, "rtprio", + int, function, pid_t, pid, struct rtprio *, rtp); + if (ARG1 == VKI_RTP_SET) { + PRE_MEM_READ( "rtprio(rtp#set)", ARG3, sizeof(struct vki_rtprio)); + } else if (ARG1 == VKI_RTP_LOOKUP) { + PRE_MEM_WRITE( "rtprio(rtp#lookup)", ARG3, sizeof(struct vki_rtprio)); + } else { + /* PHK ?? */ + } +} + +POST(sys_rtprio) +{ + if (ARG1 == VKI_RTP_LOOKUP && RES == 0) + POST_MEM_WRITE( ARG3, sizeof(struct vki_rtprio)); +} + +// freebsd6_pread 173 FREEBSD_VERS <= 10 +// x86/amd64 + +// freebsd6_pwrite 174 FREEBSD_VERS <= 10 +// x86/amd64 + +// SYS_setfib 175 +// int setfib(int fib); +PRE(sys_setfib) +{ + PRINT("sys_setfib ( %" FMT_REGWORD "d )", SARG1); + PRE_REG_READ1(int, "setfib", int, fib); +} + +// SYS_ntp_adjtime 176 +// int ntp_adjtime(struct timex *); +// @todo + +// SYS_setgid 181 +// generic + +// SYS_setegid 182 +// int setegid(gid_t egid); +PRE(sys_setegid) +{ + PRINT("sys_setegid ( %" FMT_REGWORD "u )", ARG1); + PRE_REG_READ1(int, "setegid", vki_gid_t, gid); +} + +// SYS_seteuid 183 +// int seteuid(uid_t euid); +PRE(sys_seteuid) +{ + PRINT("sys_seteuid ( %" FMT_REGWORD "u )", ARG1); + PRE_REG_READ1(long, "seteuid", vki_uid_t, uid); +} + + +#if (FREEBSD_VERS >= FREEBSD_12) + +// SYS_freebsd11_stat 188 +// int stat(char *path, struct freebsd11_stat *sb); +PRE(sys_freebsd11_stat) +{ + PRINT("sys_stat ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(int, "stat", char *, path, struct freebsd11_stat *, sb); + PRE_MEM_RASCIIZ( "stat(path)", ARG1 ); + PRE_MEM_WRITE( "stat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +POST(sys_freebsd11_stat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +// SYS_freebsd11_fstat 189 +// int fstat(int fd, struct stat *sb); +PRE(sys_freebsd11_fstat) +{ + PRINT("sys_freebsd11_fstat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,ARG2); + PRE_REG_READ2(int, "fstat", int, fd, struct stat *, sb); + PRE_MEM_WRITE( "fstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +POST(sys_freebsd11_fstat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +// SYS_freebsd11_lstat 190 +// int lstat(const char * restrict path, struct stat * restrict sb); +PRE(sys_freebsd11_lstat) +{ + PRINT("sys_lstat ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(sb, "lstat", const char *, path, struct freebsd11_stat *, sb); + PRE_MEM_RASCIIZ( "lstat(path)", ARG1 ); + PRE_MEM_WRITE( "lstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +POST(sys_freebsd11_lstat) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) ); + } +} + +#else + +PRE(sys_stat) +{ + PRINT("sys_stat ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(int, "stat", char *, path, struct stat *, sb); + PRE_MEM_RASCIIZ( "stat(path)", ARG1 ); + PRE_MEM_WRITE( "stat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +POST(sys_stat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) ); +} + + +PRE(sys_fstat) +{ + PRINT("sys_fstat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,ARG2); + PRE_REG_READ2(int, "fstat", int, fd, struct stat *, sb); + PRE_MEM_WRITE( "fstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +POST(sys_fstat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +PRE(sys_lstat) +{ + PRINT("sys_lstat ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(int, "lstat", const char *, path, struct stat *, sb); + PRE_MEM_RASCIIZ( "lstat(path)", ARG1 ); + PRE_MEM_WRITE( "lstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +POST(sys_lstat) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) ); + } +} + +#endif + +// SYS_pathconf 191 +// long pathconf(const char *path, int name); +PRE(sys_pathconf) +{ + PRINT("sys_pathconf ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "pathconf", char *, path, int, name); + PRE_MEM_RASCIIZ( "pathconf(path)", ARG1 ); +} + +// SYS_fpathconf 192 +// long fpathconf(int fd, int name); +PRE(sys_fpathconf) +{ + PRINT("sys_fpathconf ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2); + PRE_REG_READ2(long, "fpathconf", int, fd, int, name); +} + +// SYS_getrlimit 194 +// generic + +// SYS_setrlimit 195 +// generic + + +// SYS_freebsd11_getdirentries 196 +// int getdirentries(int fd, char *buf, int nbytes, long *basep); +#if (FREEBSD_VERS >= FREEBSD_12) +PRE(sys_freebsd11_getdirentries) +{ + *flags |= SfMayBlock; + PRINT("sys_freebsd11_getdirentries ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3); + PRE_REG_READ4(int, "getdirentries", + int, fd, char *, buf, + int, nbytes, + long *, basep); + PRE_MEM_WRITE( "getdirentries(buf)", ARG2, ARG3 ); + if (ARG4) + PRE_MEM_WRITE( "getdirentries(basep)", ARG4, sizeof(long) ); +} + +POST(sys_freebsd11_getdirentries) +{ + vg_assert(SUCCESS); + if (RES > 0) { + POST_MEM_WRITE( ARG2, RES ); + if ( ARG4 != 0 ) + POST_MEM_WRITE( ARG4, sizeof (long)); + } +} +#else +PRE(sys_getdirentries) +{ + *flags |= SfMayBlock; + PRINT("sys_getdirentries ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3); + PRE_REG_READ4(int, "getdirentries", + int, fd, char *, buf, + int, nbytes, + long *, basep); + PRE_MEM_WRITE( "getdirentries(buf)", ARG2, ARG3 ); + if (ARG4) + PRE_MEM_WRITE( "getdirentries(basep)", ARG4, sizeof(long) ); +} + +POST(sys_getdirentries) +{ + vg_assert(SUCCESS); + if (RES > 0) { + POST_MEM_WRITE( ARG2, RES ); + if ( ARG4 != 0 ) + POST_MEM_WRITE( ARG4, sizeof (long)); + } +} +#endif + +// SYS_freebsd6_mmap 197 +// amd64 / x86 + + +// SYS___syscall 198 +// special handling + +// freebsd6_lseek 199 FREEBSD_VERS <= 10 +// x86/amd64 + +// freebsd6_truncate 200 FREEBSD_VERS <= 10 +// x86/amd64 + +// freebsd6_ftruncate 201 FREEBSD_VERS <= 10 +// x86/amd64 + +// SYS___sysctl 202 +/* int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen); */ +/* ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 */ +PRE(sys___sysctl) +{ + PRINT("sys_sysctl ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,SARG2,ARG3,ARG4,ARG5,ARG6 ); + + int* name = (int*)ARG1; + if (ML_(safe_to_deref)(name, sizeof(int))) { + PRINT("\nmib[0]: "); + if (SARG2 >= 1) { + switch (name[0]) { + case 0: // CTL_UNSPEC + PRINT("unspec"); + break; + case 1: // CTL_KERN + PRINT("kern"); + break; + case 2: // CTL_VM + PRINT("vm"); + break; + case 3: // CTL_VFS + PRINT("vfs"); + break; + case 4: // CTL_NET + PRINT("net"); + break; + case 5: // CTL_DEBUG + PRINT("debug"); + break; + case 6: // CTL_HW + PRINT("hw"); + break; + case 7: // CTL_MACHDEP + PRINT("machdep"); + break; + case 8: // CTL _USER + PRINT("user"); + break; + case 9: //CTL_P1003_1B + PRINT("p1003_b1b"); + break; + default: + PRINT("unrecognized (%d)", ((int*)ARG1)[0]); + break; + } + } + if (SARG2 >= 2 && ML_(safe_to_deref)(name, 2*sizeof(int))) { + PRINT(" mib[1]: %d\n", name[1]); + } + } + + /* + * Special handling cases + * + * 1. kern.userstack + * This sysctl returns the address of the bottom of the user stack + * (that is the highest user stack address, since the stack grows + * downwards). Without any special handling this would return the + * address of the host userstack. We have created a stack for the + * guest (in aspacemgr) and that is the one that we want the guest + * to see. Aspacemgr is setup in m_main.c with the adresses and sizes + * saved to file static variables in that file, so we call + * VG_(get_usrstack)() to retrieve them from there. + */ + if (SARG2 >= 2 && ML_(safe_to_deref)(name, 2*sizeof(int))) { + if (name[0] == 1 && name[1] == 33) { + // kern.userstack + Word tmp = VG_(get_usrstack)(); + size_t* out = (size_t*)ARG3; + size_t* outlen = (size_t*)ARG4; + *out = tmp; + *outlen = sizeof(size_t); + SET_STATUS_Success(0); + } + } + + + PRE_REG_READ6(int, "__sysctl", int *, name, vki_u_int32_t, namelen, void *, oldp, + vki_size_t *, oldlenp, void *, newp, vki_size_t, newlen); + + // read number of ints specified in ARG2 from mem pointed to by ARG1 + PRE_MEM_READ("sysctl(name)", (Addr)ARG1, ARG2 * sizeof(int)); + + // if 'newp' is not NULL can read namelen bytes from that address + if (ARG5 != (UWord)NULL) + PRE_MEM_READ("sysctl(newp)", (Addr)ARG5, ARG6); + + // there are two scenarios for oldlenp/oldp + // 1. oldval is NULL and oldlenp is non-NULL + // this is a query of oldlenp so oldlenp will be written + // 2. Both are non-NULL + // this is a query of oldp, oldlenp will be read and oldp will + // be written + + // is oldlenp is not NULL, can write + if (ARG4 != (UWord)NULL) { + if (ARG3 != (UWord)NULL) { + // case 2 above + PRE_MEM_READ("sysctl(oldlenp)", (Addr)ARG4, sizeof(vki_size_t)); + if (ML_(safe_to_deref)((void*)(Addr)ARG4, sizeof(vki_size_t))) { + PRE_MEM_WRITE("sysctl(oldp)", (Addr)ARG3, *(vki_size_t *)ARG4); + } else { + VG_(dmsg)("Warning: Bad oldlenp address %p in sysctl\n", + (void *)(Addr)ARG4); + SET_STATUS_Failure ( VKI_EFAULT ); + } + } else { + // case 1 above + PRE_MEM_WRITE("sysctl(oldlenp)", (Addr)ARG4, sizeof(vki_size_t)); + } + } +} + +POST(sys___sysctl) +{ + if (ARG4 != (UWord)NULL) { + if (ARG3 != (UWord)NULL) { + //POST_MEM_WRITE((Addr)ARG4, sizeof(vki_size_t)); + POST_MEM_WRITE((Addr)ARG3, *(vki_size_t *)ARG4); + } else + POST_MEM_WRITE((Addr)ARG4, sizeof(vki_size_t)); + } +} + +// SYS_mlock 203 +// generic + +// SYS_munlock 204 +// generic + +// SYS_undelete 205 +// int undelete(const char *path); +PRE(sys_undelete) +{ + *flags |= SfMayBlock; + PRINT("sys_undelete ( %#" FMT_REGWORD "x(%s) )", ARG1,(char *)ARG1); + PRE_REG_READ1(int, "undelete", const char *, path); + PRE_MEM_RASCIIZ( "undelete(path)", ARG1 ); +} + +// SYS_futimes 206 +// int futimes(int fd, const struct timeval *times); +PRE(sys_futimes) +{ + PRINT("sys_lutimes ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2); + PRE_REG_READ2(long, "futimes", int, fd, struct timeval *, times); + if (ARG2 != 0) + PRE_MEM_READ( "futimes(times)", ARG2, sizeof(struct vki_timeval) ); +} + +// SYS_getpgid 207 +// generic + +// SYS_poll 209 +// generic + +// SYS_freebsd7___semctl 220 +// int semctl(int semid, int semnum, int cmd, ...); +PRE(sys_freebsd7___semctl) +{ + switch (ARG3) { + case VKI_IPC_INFO: + case VKI_SEM_INFO: + PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "semctl", + int, semid, int, semnum, int, cmd, struct seminfo *, arg); + break; + case VKI_IPC_STAT: + case VKI_SEM_STAT: + case VKI_IPC_SET: + PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "semctl", + int, semid, int, semnum, int, cmd, struct vki_semid_ds_old *, arg); + break; + case VKI_GETALL: + case VKI_SETALL: + PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "semctl", + int, semid, int, semnum, int, cmd, unsigned short *, arg); + break; + default: + PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "semctl", + int, semid, int, semnum, int, cmd); + break; + } + ML_(generic_PRE_sys_semctl)(tid, ARG1,ARG2,ARG3,ARG4); +} + +POST(sys_freebsd7___semctl) +{ + ML_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3,ARG4); +} + +// SYS_semget 221 +// int semget(key_t key, int nsems, int flag); +PRE(sys_semget) +{ + PRINT("sys_semget ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "semget", vki_key_t, key, int, nsems, int, flag); +} + +// SYS_semop 222 +// int semop(int semid, struct sembuf *array, size_t nops); +PRE(sys_semop) +{ + *flags |= SfMayBlock; + PRINT("sys_semop ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "semop", + int, semid, struct sembuf *, array, unsigned, nops); + ML_(generic_PRE_sys_semop)(tid, ARG1,ARG2,ARG3); +} + +// SYS_freebsd7_msgctl 224 +// int msgctl(int msqid, int cmd, struct msqid_ds_old *buf); +PRE(sys_freebsd7_msgctl) +{ + PRINT("sys_freebsd7_msgctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1,SARG2,ARG3 ); + + PRE_REG_READ3(int, "msgctl", int, msqid, int, cmd, struct msqid_ds_old *, buf); + + switch (ARG2 /* cmd */) { + case VKI_IPC_STAT: + PRE_MEM_WRITE( "msgctl(IPC_STAT, buf)", + ARG3, sizeof(struct vki_msqid_ds_old) ); + break; + case VKI_IPC_SET: + PRE_MEM_READ( "msgctl(IPC_SET, buf)", + ARG3, sizeof(struct vki_msqid_ds_old) ); + break; + } +} + +POST(sys_freebsd7_msgctl) +{ + switch (ARG2 /* cmd */) { + case VKI_IPC_STAT: + POST_MEM_WRITE( ARG3, sizeof(struct vki_msqid_ds_old) ); + break; + } +} + +// SYS_msgget 225 +// int msgget(key_t key, int msgflg); +PRE(sys_msgget) +{ + PRINT("sys_msgget ( %" FMT_REGWORD"d, %" FMT_REGWORD"d )",SARG1,SARG2); + PRE_REG_READ2(int, "msgget", key_t, key, int, msgflg); +} + +// SYS_msgsnd 226 +// int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); +PRE(sys_msgsnd) +{ + PRINT("sys_msgsnd ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1,ARG2,SARG3,SARG4 ); + PRE_REG_READ4(int, "msgsnd", int, msqid, struct msgbuf *, msgp, size_t, msgsz, int, msgflg); + struct vki_msgbuf *msgp = (struct vki_msgbuf *)ARG2; + PRE_MEM_READ( "msgsnd(msgp->mtype)", (Addr)&msgp->mtype, sizeof(msgp->mtype) ); + PRE_MEM_READ( "msgsnd(msgp->mtext)", (Addr)&msgp->mtext, ARG3 ); +} +// SYS_msgrcv 227 +// ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg); +PRE(sys_msgrcv) +{ + *flags |= SfMayBlock; + + PRINT("sys_msgrcv ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1,ARG2,ARG3,SARG4,SARG5 ); + PRE_REG_READ5(ssize_t, "msgrcv", int, msqid, struct msgbuf *, msgp, size_t, msgsz, + long, msgtyp, int, msgflg); + struct vki_msgbuf *msgp = (struct vki_msgbuf *)ARG2; + PRE_MEM_WRITE( "msgrcv(msgp->mtype)", (Addr)&msgp->mtype, sizeof(msgp->mtype) ); + PRE_MEM_WRITE( "msgrcv(msgp->mtext)", (Addr)&msgp->mtext, ARG3 ); +} + +POST(sys_msgrcv) +{ + struct vki_msgbuf *msgp = (struct vki_msgbuf *)ARG2; + POST_MEM_WRITE( (Addr)&msgp->mtype, sizeof(msgp->mtype) ); + POST_MEM_WRITE( (Addr)&msgp->mtext, RES ); +} + +// SYS_shmat 228 +// void * shmat(int shmid, const void *addr, int flag); +PRE(sys_shmat) +{ + UWord arg2tmp; + PRINT("sys_shmat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(void *, "shmat", + int, shmid, const void *, addr, int, flag); + arg2tmp = ML_(generic_PRE_sys_shmat)(tid, ARG1,ARG2,ARG3); + if (arg2tmp == 0) + SET_STATUS_Failure( VKI_EINVAL ); + else + ARG2 = arg2tmp; +} + +POST(sys_shmat) +{ + ML_(generic_POST_sys_shmat)(tid, RES,ARG1,ARG2,ARG3); +} + +// SYS_freebsd7_shmctl 229 +// int shmctl(int shmid, int cmd, struct shmid_ds *buf); +PRE(sys_freebsd7_shmctl) +{ + PRINT("sys_freebsd7_shmctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,SARG2,ARG3); + PRE_REG_READ3(int, "shmctl", + int, shmid, int, cmd, struct vki_shmid_ds_old *, buf); + switch (ARG2 /* cmd */) { + case VKI_IPC_STAT: + PRE_MEM_WRITE( "shmctl7(IPC_STAT, buf)", + ARG3, sizeof(struct vki_shmid_ds_old) ); + break; + case VKI_IPC_SET: + PRE_MEM_READ( "shmctl7(IPC_SET, buf)", + ARG3, sizeof(struct vki_shmid_ds_old) ); + break; + } +} + +POST(sys_freebsd7_shmctl) +{ + if (ARG2 == VKI_IPC_STAT) { + POST_MEM_WRITE( ARG3, sizeof(struct vki_shmid_ds_old) ); + } +} + +// SYS_shmdt 230 +// int shmdt(const void *addr); +PRE(sys_shmdt) +{ + PRINT("sys_shmdt ( %#" FMT_REGWORD "x )",ARG1); + PRE_REG_READ1(int, "shmdt", const void *, addr); + if (!ML_(generic_PRE_sys_shmdt)(tid, ARG1)) + SET_STATUS_Failure( VKI_EINVAL ); +} + +POST(sys_shmdt) +{ + ML_(generic_POST_sys_shmdt)(tid, RES,ARG1); +} + +// SYS_shmget 231 +// int shmget(key_t key, size_t size, int flag); +PRE(sys_shmget) +{ + PRINT("sys_shmget ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "shmget", vki_key_t, key, vki_size_t, size, int, flag); +} + + +// SYS_clock_gettime 232 +// int clock_gettime(clockid_t clock_id, struct timespec *tp); +PRE(sys_clock_gettime) +{ + PRINT("sys_clock_gettime( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2); + PRE_REG_READ2(int, "clock_gettime", + vki_clockid_t, clk_id, struct timespec *, tp); + PRE_MEM_WRITE( "clock_gettime(tp)", ARG2, sizeof(struct vki_timespec) ); +} + +POST(sys_clock_gettime) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec) ); +} + +// SYS_clock_settime 233 +// int clock_settime(clockid_t clock_id, const struct timespec *tp); +PRE(sys_clock_settime) +{ + PRINT("sys_clock_settime( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2); + PRE_REG_READ2(int, "clock_settime", + vki_clockid_t, clk_id, const struct timespec *, tp); + PRE_MEM_READ( "clock_settime(tp)", ARG2, sizeof(struct vki_timespec) ); +} + +// SYS_clock_getres 234 +// int clock_getres(clockid_t clock_id, struct timespec *tp); +PRE(sys_clock_getres) +{ + PRINT("sys_clock_getres( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2); + // Nb: we can't use "RES" as the param name because that's a macro + // defined above! + PRE_REG_READ2(int, "clock_getres", + vki_clockid_t, clock_id, struct timespec *, tp); + if (ARG2 != 0) + PRE_MEM_WRITE( "clock_getres(tp)", ARG2, sizeof(struct vki_timespec) ); +} + +POST(sys_clock_getres) +{ + if (ARG2 != 0) + POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec) ); +} + +// SYS_ktimer_create 235 +// int timer_create(clockid_t clockid, struct sigevent *restrict evp, +// timer_t *restrict timerid); +PRE(sys_timer_create) +{ + PRINT("sys_timer_create( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", SARG1,ARG2,ARG3); + PRE_REG_READ3(int, "timer_create", + vki_clockid_t, clockid, struct sigevent *, evp, + vki_timer_t *, timerid); + if (ARG2 != 0) + PRE_MEM_READ( "timer_create(evp)", ARG2, sizeof(struct vki_sigevent) ); + PRE_MEM_WRITE( "timer_create(timerid)", ARG3, sizeof(vki_timer_t) ); +} + +POST(sys_timer_create) +{ + POST_MEM_WRITE( ARG3, sizeof(vki_timer_t) ); +} + +// SYS_ktimer_delete 236 +// int timer_delete(timer_t timerid); +PRE(sys_timer_delete) +{ + PRINT("sys_timer_delete( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(long, "timer_delete", vki_timer_t, timerid); +} + +// SYS_ktimer_settime 237 +// int timer_settime(timer_t timerid, int flags, +// const struct itimerspec *restrict value, +// struct itimerspec *restrict ovalue); +PRE(sys_timer_settime) +{ + PRINT("sys_timer_settime( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1,SARG2,ARG3,ARG4); + PRE_REG_READ4(int, "timer_settime", + vki_timer_t, timerid, int, flags, + const struct itimerspec *, value, + struct itimerspec *, ovalue); + PRE_MEM_READ( "timer_settime(value)", ARG3, + sizeof(struct vki_itimerspec) ); + if (ARG4 != 0) + PRE_MEM_WRITE( "timer_settime(ovalue)", ARG4, + sizeof(struct vki_itimerspec) ); +} + +POST(sys_timer_settime) +{ + if (ARG4 != 0) + POST_MEM_WRITE( ARG4, sizeof(struct vki_itimerspec) ); +} + +// SYS_ktimer_gettime 238 +// int timer_gettime(timer_t timerid, struct itimerspec *value); +PRE(sys_timer_gettime) +{ + PRINT("sys_timer_gettime( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1,ARG2); + PRE_REG_READ2(long, "timer_gettime", + vki_timer_t, timerid, struct itimerspec *, value); + PRE_MEM_WRITE( "timer_gettime(value)", ARG2, + sizeof(struct vki_itimerspec)); +} + +POST(sys_timer_gettime) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_itimerspec) ); +} + +// SYS_ktimer_getoverrun 239 +// int timer_getoverrun(timer_t timerid); +PRE(sys_timer_getoverrun) +{ + PRINT("sys_timer_getoverrun( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "timer_getoverrun", vki_timer_t, timerid); +} + +// SYS_nanosleep 240 +// generic + +// SYS_ffclock_getcounter 241 +// int ffclock_getcounter(ffcounter *ffcount); +// @todo + +// SYS_ffclock_setestimate 242 +// int ffclock_setestimate(struct ffclock_estimate *cest); +// @todo + +// SYS_ffclock_getestimate 243 +// int ffclock_getestimate(struct ffclock_estimate *cest); +// @todo + +// SYS_clock_nanosleep 244 +// int clock_nanosleep(clockid_t clock_id, int flags, +// const struct timespec *rqtp, struct timespec *rmtp); +PRE(sys_clock_nanosleep) +{ + *flags |= SfMayBlock|SfPostOnFail; + PRINT("sys_clock_nanosleep ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + SARG1, SARG2, ARG3, ARG4); + PRE_REG_READ4(int, "clock_nanosleep", clockid_t, clock_id, int, flags, + const struct timespec *, rqtp, struct timespec *, rmtp); + PRE_MEM_READ("clock_nanosleep(rqtp)", ARG1, sizeof(struct vki_timespec)); + if (ARG2 != 0) + PRE_MEM_WRITE( "clock_nanosleep(rmtp)", ARG2, sizeof(struct vki_timespec) ); + +} + +POST(sys_clock_nanosleep) +{ + if (ARG2 != 0) + PRE_MEM_WRITE( "clock_nanosleep(rmtp)", ARG2, sizeof(struct vki_timespec) ); +} + +// SYS_clock_getcpuclockid2 247 +// no manpage for this +// @todo + +// SYS_ntp_gettime 248 +// int ntp_gettime(struct ntptimeval *); +// @todo + +// SYS_minherit 250 +// int minherit(void *addr, size_t len, int inherit); +PRE(sys_minherit) +{ + PRINT("sys_minherit( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "minherit", + void *, addr, vki_size_t, len, int, inherit); + if (ARG2 != 0) + PRE_MEM_WRITE( "minherit(addr)", ARG1,ARG2 ); +} + +POST(sys_minherit) +{ + if (ARG2 != 0) + POST_MEM_WRITE( ARG1, ARG2 ); +} + +// SYS_rfork 251 +// x86/amd64 not functional + +// SYS_issetugid 253 +// int issetugid(void); +PRE(sys_issetugid) +{ + PRINT("%s", "sys_issetugid ()"); + PRE_REG_READ0(long, "issetugid"); +} + +// SYS_lchown 254 +// generic + +// SYS_aio_read 255 +// int aio_read(struct aiocb *iocb); +PRE(sys_aio_read) +{ + PRINT("sys_aio_read ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "aio_read", struct vki_aiocb *, iocb); + PRE_MEM_READ("aio_read(iocb)", ARG1, sizeof(struct vki_aiocb)); + if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) { + struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1; + PRE_MEM_WRITE( "aio_read(iocb->aio_offset)", (Addr)iocb, sizeof(struct vki_aiocb)); + } +} + +POST(sys_aio_read) +{ + if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) { + struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1; + POST_MEM_WRITE((Addr)iocb, sizeof(struct vki_aiocb)); + } +} + +// SYS_aio_write 256 +// int aio_write(struct aiocb *iocb); +PRE(sys_aio_write) +{ + PRINT("sys_aio_write ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "aio_write", struct vki_aiocb *, iocb); + PRE_MEM_READ("aio_read(iocb)", ARG1, sizeof(struct vki_aiocb)); + if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) { + struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1; + PRE_MEM_WRITE( "aio_write(iocb->aio_offset)", (Addr)iocb, sizeof(struct vki_aiocb)); + } +} + +POST(sys_aio_write) +{ + if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) { + struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1; + PRE_MEM_WRITE( "aio_write(iocb->aio_offset)", (Addr)iocb, sizeof(struct vki_aiocb)); + } +} + +// SYS_lio_listio 257 +// int lio_listio(int mode, struct aiocb * const list[], int nent, +// struct sigevent *sig); +PRE(sys_lio_listio) +{ + PRINT("sys_lio_listio ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", + SARG1, ARG2, SARG3, ARG4); + PRE_REG_READ4(int, "lio_listio", int, mode, struct aiocb * const *, list, int, nent, + struct sigevent *,sig); + PRE_MEM_READ("lio_listio(list)", ARG2, ARG3*sizeof(struct vki_aiocb *)); + // loop check elements + if (ML_(safe_to_deref)((struct vki_aiocb **)ARG2, ARG3*sizeof(struct vki_aiocb *))) { + struct vki_aiocb** list = (struct vki_aiocb **)ARG2; + for (int i = 0; i < (int)ARG3; ++i) { + if (list[i]) { + PRE_MEM_READ("lio_listio(list[?])", (Addr)list[i], ARG3*sizeof(struct vki_aiocb)); + } + // @todo + // figure out what gets read/written + // when list[i]->aio_lio_opcode == VKI_LIO_READ and + // when list[i]->aio_lio_opcode == VKI_LIO_WRITE + //if (ML_(safe_to_deref)(list[i], ARG3*sizeof(struct vki_aiocb))) { + //} + } + } + + if (ARG1 & VKI_LIO_WAIT) { + *flags |= SfMayBlock; + } + + if (ARG4 && (ARG1 == VKI_LIO_NOWAIT)) { + PRE_MEM_READ("lio_listio(sig)", ARG4, sizeof(struct vki_sigevent)); + } +} + +// SYS_freebsd11_getdents 272 +// generic + +// SYS_lchmod 274 +// int lchmod(const char *path, mode_t mode); +PRE(sys_lchmod) +{ + PRINT("sys_lchmod ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(int, "lchmod", const char *, path, vki_mode_t, mode); + PRE_MEM_RASCIIZ( "lchmod(path)", ARG1 ); +} + +// SYS_lutimes 276 +// int lutimes(const char *path, const struct timeval *times); +PRE(sys_lutimes) +{ + PRINT("sys_lutimes ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(int, "lutimes", char *, path, struct timeval *, times); + PRE_MEM_RASCIIZ( "lutimes(path)", ARG1 ); + if (ARG2 != 0) + PRE_MEM_READ( "lutimes(times)", ARG2, sizeof(struct vki_timeval) ); +} + +// SYS_freebsd11_nstat 278 +// @todo, maybe + +// SYS_freebsd11_nfstat 279 +// @todo, maybe + +// SYS_freebsd11_nlstat 280 +// @todo, maybe + +// SYS_preadv 289 +// amd64 / x86 + +// SYS_pwritev 290 +// amd64 / x86 + +// SYS_fhopen 298 +// int fhopen(const fhandle_t *fhp, int flags); +PRE(sys_fhopen) +{ + PRINT("sys_open ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2); + PRE_REG_READ2(int, "fhopen", + struct fhandle_t *, fhp, int, flags); + PRE_MEM_READ( "fhopen(fhp)", ARG1, sizeof(struct vki_fhandle) ); + + /* Otherwise handle normally */ + *flags |= SfMayBlock; +} + +POST(sys_fhopen) +{ + vg_assert(SUCCESS); + if (!ML_(fd_allowed)(RES, "fhopen", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_nameless)(tid, RES); + } +} + +// SYS_freebsd11_fhstat 299 +// int fhstat(const fhandle_t *fhp, struct stat *sb); +#if (FREEBSD_VERS >= FREEBSD_12) +PRE(sys_freebsd11_fhstat) +{ + PRINT("sys_freebsd11_fhstat ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2); + PRE_REG_READ2(int, "fhstat", struct fhandle *, fhp, struct freebd11_stat *, sb); + PRE_MEM_READ( "fhstat(fhp)", ARG1, sizeof(struct vki_fhandle) ); + PRE_MEM_WRITE( "fhstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +POST(sys_freebsd11_fhstat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) ); +} +#else +PRE(sys_fhstat) +{ + PRINT("sys_fhstat ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2); + PRE_REG_READ2(int, "fhstat", struct fhandle *, fhp, struct stat *, sb); + PRE_MEM_READ( "fhstat(fhp)", ARG1, sizeof(struct vki_fhandle) ); + PRE_MEM_WRITE( "fhstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +POST(sys_fhstat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) ); +} + +#endif + +// SYS_modnext 300 +// int modnext(int modid); +PRE(sys_modnext) +{ + PRINT("sys_modnext ( %" FMT_REGWORD "d )",SARG1); + PRE_REG_READ1(int, "modnext", int, modid); +} + +// SYS_modstat 301 +// int modstat(int modid, struct module_stat *stat); +PRE(sys_modstat) +{ + PRINT("sys_modstat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2); + PRE_REG_READ2(int, "modstat", int, modid, struct module_stat *, buf); + PRE_MEM_WRITE( "modstat(stat)", ARG2, sizeof(struct vki_module_stat) ); +} + +POST(sys_modstat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_module_stat) ); +} + +// SYS_modfnext 302 +// int modfnext(int modid); +PRE(sys_modfnext) +{ + PRINT("sys_modfnext ( %" FMT_REGWORD "d )",SARG1); + PRE_REG_READ1(int, "modfnext", int, modid); +} + +// SYS_modfind 303 +// int modfind(const char *modname); +PRE(sys_modfind) +{ + PRINT("sys_modfind ( %#" FMT_REGWORD "x )",ARG1); + PRE_REG_READ1(long, "modfind", char *, modname); + PRE_MEM_RASCIIZ( "modfind(modname)", ARG1 ); +} + +// SYS_kldload 304 +// int kldload(const char *file); +PRE(sys_kldload) +{ + PRINT("sys_kldload ( %#" FMT_REGWORD "x(%s) )", ARG1, (char *)ARG1); + PRE_REG_READ1(int, "kldload", const char *, "file"); + PRE_MEM_RASCIIZ( "kldload(file)", ARG1 ); +} + +// SYS_kldunload 305 +// int kldunload(int fileid); +PRE(sys_kldunload) +{ + PRINT("sys_kldunload ( %" FMT_REGWORD "u )", ARG1); + PRE_REG_READ1(int, "kldunload", int, "fileid"); +} + +// SYS_kldfind 306 +// int kldfind(const char *file); +PRE(sys_kldfind) +{ + PRINT("sys_kldfind ( %#" FMT_REGWORD "x(%s) )", ARG1, (char *)ARG1); + PRE_REG_READ1(int, "kldfind", const char *, file); + PRE_MEM_RASCIIZ( "kldfind(file)", ARG1 ); +} + +// SYS_kldnext 307 +// int kldnext(int fileid); +PRE(sys_kldnext) +{ + PRINT("sys_kldnext ( %" FMT_REGWORD "u )", ARG1); + PRE_REG_READ1(int, "kldnext", int, fileid); +} + +// SYS_kldstat 308 +// int kldstat(int fileid, struct kld_file_stat *stat); +PRE(sys_kldstat) +{ + PRINT("sys_kldstat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2); + PRE_REG_READ2(int, "kldstat", int, fileid, struct kld_file_stat*, stat); + PRE_MEM_WRITE("kldstat(stat)", ARG2, sizeof(struct vki_kld_file_stat)); +} + +POST(sys_kldstat) +{ + POST_MEM_WRITE(ARG2, sizeof(struct vki_kld_file_stat)); +} + +// SYS_kldfirstmod 309 +// int kldfirstmod(int fileid); +PRE(sys_kldfirstmod) +{ + PRINT("sys_kldfirstmod ( %" FMT_REGWORD "u )", ARG1); + PRE_REG_READ1(int, "kldfirstmod", int, fileid); +} + +// SYS_setresuid 311 +// int setresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +PRE(sys_setresuid) +{ + PRINT("sys_setresuid ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3); + PRE_REG_READ3(int, "setresuid", + vki_uid_t, ruid, vki_uid_t, euid, vki_uid_t, suid); +} + +// SYS_setresgid 312 +// int setresgid(gid_t rgid, gid_t egid, gid_t sgid); +PRE(sys_setresgid) +{ + PRINT("sys_setresgid ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3); + PRE_REG_READ3(int, "setresgid", + vki_gid_t, rgid, vki_gid_t, egid, vki_gid_t, sgid); +} + +// SYS_aio_return 314 +// ssize_t aio_return(struct aiocb *iocb); +PRE(sys_aio_return) +{ + PRINT("sys_aio_return ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(ssize_t, "aio_return", struct aiocb *, iocb); + // not too clear if this is read-only, sounds like it from the man page + // but it isn't const + PRE_MEM_READ("aio_return(iocb)", ARG1, sizeof(struct vki_aiocb)); +} + +// SYS_aio_suspend 315 +// int aio_suspend(const struct aiocb *const iocbs[], int niocb, +// const struct timespec *timeout); +PRE(sys_aio_suspend) +{ + PRINT("sys_aio_suspend ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ3(int, "aio_suspend", struct aiocb **, iocbs, int, nbiocb, const struct timespec*, timeout); + PRE_MEM_READ("aio_suspend(iocbs)", ARG1, ARG2*sizeof(struct vki_aiocb)); + PRE_MEM_READ("aio_suspend(timeout)", ARG3, sizeof(struct vki_timespec)); +} + +// SYS_aio_cancel 316 +// int aio_cancel(int fildes, struct aiocb *iocb); +PRE(sys_aio_cancel) +{ + PRINT("sys_aio_cancel ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2); + PRE_REG_READ2(int, "aio_cancel", int, fildex, struct aiocb *, iocb); + if (ARG2) { + PRE_MEM_READ("aio_cancel(iocb)", ARG2, sizeof(struct vki_aiocb)); + } +} + +// SYS_aio_error 317 +// int aio_error(const struct aiocb *iocb); +PRE(sys_aio_error) +{ + PRINT("sys_aio_error ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(ssize_t, "aio_error", struct aiocb *, iocb); + PRE_MEM_READ("aio_error(iocb)", ARG1, sizeof(struct vki_aiocb)); +} + +// SYS_yield 321 +int yield(void); +PRE(sys_yield) +{ + *flags |= SfMayBlock; + PRINT("%s", "yield()"); + PRE_REG_READ0(long, "yield"); +} + +// SYS_mlockall 324 +// generic + +// SYS_munlockall 325 +// int munlockall(void); +PRE(sys_munlockall) +{ + *flags |= SfMayBlock; + PRINT("%s", "sys_munlockall ( )"); + PRE_REG_READ0(int, "munlockall"); +} + +// SYS___getcwd 326 +// int __getcwd(char *buf, size_t buflen); +PRE(sys___getcwd) +{ + PRINT("sys___getcwd ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2); + PRE_REG_READ2(long, "__getcwd", char *, buf, unsigned int, buflen); + PRE_MEM_WRITE( "__getcwd(buf)", ARG1, ARG2 ); +} + +POST(sys___getcwd) +{ + vg_assert(SUCCESS); + if (RES == 0) { + // QQQ it is unclear if this is legal or not, but the + // QQQ kernel just wrote it there... + // QQQ Why oh why didn't phk return the length from __getcwd()? + UInt len = VG_(strlen) ( (char *)ARG1 ) + 1; + POST_MEM_WRITE( ARG1, len ); + } +} + +//SYS_sched_setparam 327 +// int sched_setparam(pid_t pid, const struct sched_param *param); +PRE(sys_sched_setparam) +{ + PRINT("sched_setparam ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2 ); + PRE_REG_READ2(int, "sched_setparam", + vki_pid_t, pid, struct sched_param *, param); + PRE_MEM_READ( "sched_setparam(param)", ARG2, sizeof(struct vki_sched_param) ); +} + +POST(sys_sched_setparam) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_sched_param) ); +} + +// SYS_sched_getparam 328 +// int sched_getparam(pid_t pid, struct sched_param *param); +PRE(sys_sched_getparam) +{ + PRINT("sched_getparam ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2 ); + PRE_REG_READ2(int, "sched_getparam", + vki_pid_t, pid, struct sched_param *, param); + PRE_MEM_WRITE( "sched_getparam(param)", ARG2, sizeof(struct vki_sched_param) ); +} + +POST(sys_sched_getparam) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_sched_param) ); +} + +// SYS_sched_setscheduler 329 +// int sched_setscheduler(pid_t pid, int policy, +// const struct sched_param *param); +PRE(sys_sched_setscheduler) +{ + PRINT("sys_sched_setscheduler ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1,SARG2,ARG3); + PRE_REG_READ3(int, "sched_setscheduler", + vki_pid_t, pid, int, policy, struct sched_param *, param); + if (ARG3 != 0) + PRE_MEM_READ("sched_setscheduler(param)", + ARG3, sizeof(struct vki_sched_param)); +} + +// SYS_sched_getscheduler 330 +// int sched_getscheduler(pid_t pid); +PRE(sys_sched_getscheduler) +{ + PRINT("sys_sched_getscheduler ( %" FMT_REGWORD "d )", SARG1); + PRE_REG_READ1(int, "sched_getscheduler", vki_pid_t, pid); +} + +// SYS_sched_yield 331 +// int sched_yield(void); +PRE(sys_sched_yield) +{ + *flags |= SfMayBlock; + PRINT("sched_yield()"); + PRE_REG_READ0(int, "sched_yield"); +} + +// SYS_sched_get_priority_max 332 +// int sched_get_priority_max(int policy); +PRE(sys_sched_get_priority_max) +{ + PRINT("sched_get_priority_max ( %" FMT_REGWORD "u )", ARG1); + PRE_REG_READ1(long, "sched_get_priority_max", int, policy); +} + +// SYS_sched_get_priority_min 333 +// int sched_get_priority_min(int policy); +PRE(sys_sched_get_priority_min) +{ + PRINT("sched_get_priority_min ( %" FMT_REGWORD "u )", ARG1); + PRE_REG_READ1(long, "sched_get_priority_min", int, policy); +} + +// SYS_sched_rr_get_interval 334 +// int sched_rr_get_interval(pid_t pid, struct timespec *interval); +PRE(sys_sched_rr_get_interval) +{ + PRINT("sys_sched_rr_get_interval ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2); + PRE_REG_READ2(int, "sched_rr_get_interval", vki_pid_t, pid, struct vki_timespec *,interval); + PRE_MEM_WRITE("sys_sched_rr_get_interval(interval)", ARG2, sizeof(struct vki_timespec)); +} + +POST(sys_sched_rr_get_interval) +{ + POST_MEM_WRITE(ARG2, sizeof(struct vki_timespec)); +} + +// SYS_utrace 335 +// int utrace(const void *addr, size_t len); +PRE(sys_utrace) +{ + PRINT("sys_utrace ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2); + PRE_REG_READ2(int, "utrace", const void *, addr, vki_size_t, len); + PRE_MEM_READ( "utrace(addr)", ARG2, ARG3 ); +} + +// SYS_kldsym 337 +// int kldsym(int fileid, int cmd, void *data); +PRE(sys_kldsym) +{ + PRINT("sys_kldsym ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3 ); + PRE_REG_READ3(int, "kldsym", int, fileid, int, cmd, void*, data); + PRE_MEM_READ( "kldsym(data)", ARG3, sizeof(struct vki_kld_sym_lookup) ); + struct vki_kld_sym_lookup *kslp = (struct vki_kld_sym_lookup *)ARG3; + if (ML_(safe_to_deref)(kslp, sizeof(struct vki_kld_sym_lookup))) { + PRE_MEM_RASCIIZ( "kldsym(data.symname)", (Addr)kslp->symname ); + } +} + +POST(sys_kldsym) +{ + struct vki_kld_sym_lookup *kslp = (struct vki_kld_sym_lookup *)ARG3; + POST_MEM_WRITE( (Addr)&kslp->symvalue, sizeof(kslp->symvalue) ); + POST_MEM_WRITE( (Addr)&kslp->symsize, sizeof(kslp->symsize) ); +} + +// SYS_jail 338 +// int jail(struct jail *jail); +PRE(sys_jail) +{ + PRINT("sys_jail ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "jail", struct jail *, jail); + PRE_MEM_READ( "jail(jail)", ARG1, sizeof(struct vki_jail) ); +} + +// SYS_nnpfs_syscall 338 +// @todo + +// SYS_sigprocmask 340 +// int sigprocmask(int how, const sigset_t * restrict set, +// sigset_t * restrict oset); +PRE(sys_sigprocmask) +{ + PRINT("sys_sigprocmask ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "sigprocmask", + int, how, vki_sigset_t *, set, vki_sigset_t *, oset); + if (ARG2 != 0) + PRE_MEM_READ( "sigprocmask(set)", ARG2, sizeof(vki_sigset_t)); + if (ARG3 != 0) + PRE_MEM_WRITE( "sigprocmask(oset)", ARG3, sizeof(vki_sigset_t)); + + if (ARG2 != 0 && + !ML_(safe_to_deref)((void *)(Addr)ARG2, sizeof(vki_sigset_t))) { + VG_(dmsg)("Warning: Bad set handler address %p in sigprocmask\n", + (void *)(Addr)ARG2); + SET_STATUS_Failure ( VKI_EFAULT ); + } else if (ARG3 != 0 && + !ML_(safe_to_deref)((void *)(Addr)ARG3, sizeof(vki_sigset_t))) { + VG_(dmsg)("Warning: Bad oldset address %p in sigprocmask\n", + (void *)(Addr)ARG3); + SET_STATUS_Failure ( VKI_EFAULT ); + } else { + SET_STATUS_from_SysRes(VG_(do_sys_sigprocmask)(tid, ARG1 /*how*/, + (vki_sigset_t*)(Addr)ARG2, + (vki_sigset_t*)(Addr)ARG3)); + } + + if (SUCCESS) + *flags |= SfPollAfter; +} + +POST(sys_sigprocmask) +{ + vg_assert(SUCCESS); + if (RES == 0 && ARG3 != 0) + POST_MEM_WRITE( ARG3, sizeof(vki_sigset_t)); +} + +// SYS_sigsuspend 341 +// int sigsuspend(const sigset_t *sigmask); +PRE(sys_sigsuspend) +{ + *flags |= SfMayBlock; + PRINT("sys_sigsuspend ( %#" FMT_REGWORD "x )", ARG1 ); + PRE_REG_READ1(int, "sigsuspend", const vki_sigset_t *, sigmask); + PRE_MEM_READ( "sigsuspend(sigmask)", ARG1, sizeof(vki_sigset_t) ); + if (ARG1) { + ARG1 = ML_(make_safe_mask)("syswrap.sigsuspend.1", (Addr)ARG1); + } +} + +POST(sys_sigsuspend) +{ + ML_(free_safe_mask) ( (Addr)ARG1 ); +} + +// SYS_sigpending 343 +// int sigpending(sigset_t *set); +PRE(sys_sigpending) +{ + PRINT( "sys_sigpending ( %#" FMT_REGWORD "x )", ARG1 ); + PRE_REG_READ1(int, "sigpending", vki_sigset_t *, set); + PRE_MEM_WRITE( "sigpending(set)", ARG1, sizeof(vki_sigset_t)); +} + +POST(sys_sigpending) +{ + POST_MEM_WRITE( ARG1, sizeof(vki_sigset_t) ) ; +} + + +// SYS_sigtimedwait 345 +// int sigtimedwait(const sigset_t *restrict set, siginfo_t *restrict info, +// const struct timespec *restrict timeout); +PRE(sys_sigtimedwait) +{ + *flags |= SfMayBlock; + PRINT("sys_sigtimedwait ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "sigtimedwait", + const vki_sigset_t *, set, vki_siginfo_t *, info, + const struct timespec *, timeout); + if (ARG1 != 0) + PRE_MEM_READ( "sigtimedwait(set)", ARG1, sizeof(vki_sigset_t)); + if (ARG2 != 0) + PRE_MEM_WRITE( "sigtimedwait(info)", ARG2, sizeof(vki_siginfo_t) ); + if (ARG3 != 0) + PRE_MEM_READ( "sigtimedwait(timeout)", + ARG3, sizeof(struct vki_timespec) ); +} + +POST(sys_sigtimedwait) +{ + if (ARG2 != 0) + POST_MEM_WRITE( ARG2, sizeof(vki_siginfo_t) ); +} + +// SYS_sigwaitinfo 346 +// int sigwaitinfo(const sigset_t * restrict set, siginfo_t * restrict info); +PRE(sys_sigwaitinfo) +{ + *flags |= SfMayBlock; + PRINT("sys_sigwaitinfo ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + ARG1,ARG2); + PRE_REG_READ2(int, "sigwaitinfo", + const vki_sigset_t *, set, vki_siginfo_t *, info); + if (ARG1 != 0) + PRE_MEM_READ( "sigwaitinfo(set)", ARG1, sizeof(vki_sigset_t)); + if (ARG2 != 0) + PRE_MEM_WRITE( "sigwaitinfo(info)", ARG2, sizeof(vki_siginfo_t) ); +} + +POST(sys_sigwaitinfo) +{ + if (ARG2 != 0) + POST_MEM_WRITE( ARG2, sizeof(vki_siginfo_t) ); +} + +// SYS___acl_get_file 347 +// int __acl_get_file(const char *path, acl_type_t type, struct acl *aclp); +PRE(sys___acl_get_file) +{ + PRINT("sys___acl_get_file ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "acl_get_file", + const char *, path, int, type, struct vki_acl *, aclp); + PRE_MEM_RASCIIZ("acl_get_file(path", ARG1); + PRE_MEM_WRITE( "acl_get_file(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +POST(sys___acl_get_file) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG3, sizeof(struct vki_acl) ); + } +} + +// SYS___acl_set_file 348 +// int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp); +PRE(sys___acl_set_file) +{ + PRINT("sys___acl_set_file ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "acl_set_file", + const char *, path, int, type, struct vki_acl *, aclp); + PRE_MEM_RASCIIZ("acl_set_file(path", ARG1); + PRE_MEM_READ("acl_set_file(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +// SYS___acl_get_fd 349 +// int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp); +PRE(sys___acl_get_fd) +{ + PRINT("sys___acl_get_fd ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "acl_get_fd", + int, fd, int, type, struct vki_acl *, aclp); + PRE_MEM_WRITE( "acl_get_file(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +POST(sys___acl_get_fd) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG3, sizeof(struct vki_acl) ); + } +} + +// SYS___acl_set_fd 350 +// int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp); +PRE(sys___acl_set_fd) +{ + PRINT("sys___acl_set_fd ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "acl_set_fd", + int, filedes, int, type, struct vki_acl *, aclp); + PRE_MEM_READ( "acl_get_file(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +// SYS___acl_delete_file 351 +// int __acl_delete_file(const char *path, acl_type_t type); +PRE(sys___acl_delete_file) +{ + PRINT("sys___acl_delete_file ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG2); + PRE_MEM_RASCIIZ("acl_set_file(path", ARG1); + PRE_REG_READ2(int, "acl_delete_file", + const char *, path, int, type); +} +// SYS___acl_delete_fd 352 +// int __acl_delete_fd(int filedes, acl_type_t type); +PRE(sys___acl_delete_fd) +{ + PRINT("sys___acl_delete_fd ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG2); + PRE_REG_READ2(int, "acl_delete_fd", + int, filedes, int, acltype); +} + +// SYS___acl_aclcheck_file 353 +// int __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp); +PRE(sys___acl_aclcheck_file) +{ + PRINT("sys___acl_aclcheck_file ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "acl_aclcheck_file", + const char *, path, int, type, struct vki_acl *, aclp); + PRE_MEM_RASCIIZ("acl_set_file(path", ARG1); + PRE_MEM_READ( "acl_aclcheck_file(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +// SYS___acl_aclcheck_fd 354 +// int __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp); +PRE(sys___acl_aclcheck_fd) +{ + PRINT("sys___acl_aclcheck_fd ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "acl_aclcheck_fd", + int, fd, int, type, struct vki_acl *, aclp); + PRE_MEM_READ( "acl_aclcheck_fd(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +// SYS_extattrctl 355 +// no manpage? +// syscalls.master: int extattrctl(_In_z_ const char *path, int cmd, _In_z_opt_ const char *filename, int attrnamespace, _In_z_ const char *attrname); +PRE(sys_extattrctl) +{ + PRINT("sys_extattrctl ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", ARG1,SARG2,ARG3,SARG4,ARG5); + PRE_REG_READ5(ssize_t, "extattrctl", + const char *, path, int, cmd, const char *, filename, int, attrnamespace, const char *, attrname); + PRE_MEM_RASCIIZ("extattrctl(path)", ARG1); + PRE_MEM_RASCIIZ("extattrctl(filename)", ARG3); + PRE_MEM_RASCIIZ("extattrctl(attrname)", ARG5); +} + +// SYS_extattr_set_file 356 +// ssize_t extattr_set_file(const char *path, int attrnamespace, +// const char *attrname, const void *data, size_t nbytes); +PRE(sys_extattr_set_file) +{ + PRINT("sys_extattr_set_file ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,SARG2,ARG3,ARG4,ARG5); + PRE_REG_READ5(ssize_t, "extattr_set_file", + const char *, path, int, attrnamespace, const char *, attrname, const void *, data, size_t, nbytes); + PRE_MEM_RASCIIZ("extattr_set_file(path)", ARG1); + PRE_MEM_RASCIIZ("extattr_set_file(attrname)", ARG3); + PRE_MEM_READ("extattr_set_file(data)", ARG4, ARG5); +} + +// SYS_extattr_get_file 357 +// ssize_t extattr_get_file(const char *path, int attrnamespace, +// const char *attrname, void *data, size_t nbytes); +PRE(sys_extattr_get_file) +{ + PRINT("sys_extattr_get_file ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,SARG2,ARG3,ARG4,ARG5); + PRE_REG_READ5(ssize_t, "extattr_get_file", + const char *, path, int, attrnamespace, const char *, attrname, void *, data, size_t, nbytes); + PRE_MEM_RASCIIZ("extattr_get_file(path)", ARG1); + PRE_MEM_RASCIIZ("extattr_get_file(attrname)", ARG3); + if (ARG4) { + PRE_MEM_WRITE("extattr_get_file(data)", ARG4, ARG5); + } +} + +POST(sys_extattr_get_file) +{ + if (ARG4) { + POST_MEM_WRITE(ARG4, ARG5); + } +} + +// SYS_extattr_delete_file 358 +// int extattr_delete_file(const char *path, int attrnamespace, +// const char *attrname); +PRE(sys_extattr_delete_file) +{ + PRINT("sys_extattr_delete_file ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", ARG1,SARG2,ARG3); + PRE_REG_READ3(ssize_t, "extattr_delete_file", + const char *, path, int, attrnamespace, const char *, attrname); + PRE_MEM_RASCIIZ("extattr_delete_file(path)", ARG1); + PRE_MEM_RASCIIZ("extattr_delete_file(attrname)", ARG3); +} + +// SYS_aio_waitcomplete 359 +// ssize_t aio_waitcomplete(struct aiocb **iocbp, struct timespec *timeout); +PRE(sys_aio_waitcomplete) +{ + *flags |= SfMayBlock; + PRINT("sys_aio_waitcomplete ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1,ARG2); + PRE_REG_READ2(ssize_t, "aio_waitcomplete", struct aiocb **, iocbp, struct timespec *, timeout); + if (ARG2) { + PRE_MEM_READ("aio_waitcomplete(timeout", ARG2, sizeof(struct vki_timespec)); + } + PRE_MEM_WRITE( "aio_waitcomplete(iocbp)", ARG1, sizeof(struct aiocb *)); +} + +POST(sys_aio_waitcomplete) +{ + POST_MEM_WRITE(ARG1, sizeof(struct aiocb *)); +} + +// SYS_getresuid 360 +// int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); +PRE(sys_getresuid) +{ + PRINT("sys_getresuid ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "getresuid", + vki_uid_t *, ruid, vki_uid_t *, euid, vki_uid_t *, suid); + PRE_MEM_WRITE( "getresuid(ruid)", ARG1, sizeof(vki_uid_t) ); + PRE_MEM_WRITE( "getresuid(euid)", ARG2, sizeof(vki_uid_t) ); + PRE_MEM_WRITE( "getresuid(suid)", ARG3, sizeof(vki_uid_t) ); +} + +POST(sys_getresuid) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG1, sizeof(vki_uid_t) ); + POST_MEM_WRITE( ARG2, sizeof(vki_uid_t) ); + POST_MEM_WRITE( ARG3, sizeof(vki_uid_t) ); + } +} + +// SYS_getresgid 361 +// int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); +PRE(sys_getresgid) +{ + PRINT("sys_getresgid ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "getresgid", + vki_gid_t *, rgid, vki_gid_t *, egid, vki_gid_t *, sgid); + PRE_MEM_WRITE( "getresgid(rgid)", ARG1, sizeof(vki_gid_t) ); + PRE_MEM_WRITE( "getresgid(egid)", ARG2, sizeof(vki_gid_t) ); + PRE_MEM_WRITE( "getresgid(sgid)", ARG3, sizeof(vki_gid_t) ); +} + +POST(sys_getresgid) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG1, sizeof(vki_gid_t) ); + POST_MEM_WRITE( ARG2, sizeof(vki_gid_t) ); + POST_MEM_WRITE( ARG3, sizeof(vki_gid_t) ); + } +} + +// SYS_kqueue 362 +// int kqueue(void); +PRE(sys_kqueue) +{ + PRINT("%s", "sys_kqueue ()"); + PRE_REG_READ0(omt, "kqueue"); +} + +POST(sys_kqueue) +{ + if (!ML_(fd_allowed)(RES, "kqueue", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) { + ML_(record_fd_open_nameless)(tid, RES); + } + } +} + +// SYS_freebsd11_kevent 363 +// int kevent(int kq, const struct kevent *changelist, int nchanges, +// struct kevent *eventlist, int nevents, +// const struct timespec *timeout); +#if (FREEBSD_VERS >= FREEBSD_12) +PRE(sys_freebsd11_kevent) +{ + PRINT("sys_freebsd11_kevent ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )\n", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6); + PRE_REG_READ6(int, "kevent", + int, fd, const struct vki_kevent_freebsd11 *, changelist, int, nchanges, + struct vki_kevent_freebsd11 *, eventlist, int, nevents, + struct timespec *, timeout); + if (ARG2 != 0 && ARG3 != 0) + PRE_MEM_READ( "kevent(changelist)", ARG2, sizeof(struct vki_kevent_freebsd11)*ARG3 ); + if (ARG4 != 0 && ARG5 != 0) + PRE_MEM_WRITE( "kevent(eventlist)", ARG4, sizeof(struct vki_kevent_freebsd11)*ARG5); + if (ARG5 != 0) + *flags |= SfMayBlock; + if (ARG6 != 0) + PRE_MEM_READ( "kevent(timeout)", + ARG6, sizeof(struct vki_timespec)); +} + +POST(sys_freebsd11_kevent) +{ + vg_assert(SUCCESS); + if ((Word)RES != -1) { + if (ARG4 != 0) + POST_MEM_WRITE( ARG4, sizeof(struct vki_kevent_freebsd11)*RES) ; + } +} +#else +PRE(sys_kevent) +{ + *flags |= SfMayBlock; + PRINT("sys_kevent ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )\n", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6); + PRE_REG_READ6(int, "kevent", + int, fd, struct vki_kevent_freebsd11 *, changelist, int, nchanges, + struct vki_kevent_freebsd11 *, eventlist, int, nevents, + struct timespec *, timeout); + if (ARG2 != 0 && ARG3 != 0) + PRE_MEM_READ( "kevent(changelist)", ARG2, sizeof(struct vki_kevent_freebsd11)*ARG3 ); + if (ARG4 != 0 && ARG5 != 0) + PRE_MEM_WRITE( "kevent(eventlist)", ARG4, sizeof(struct vki_kevent_freebsd11)*ARG5); + if (ARG6 != 0) + PRE_MEM_READ( "kevent(timeout)", + ARG6, sizeof(struct vki_timespec)); +} + +POST(sys_kevent) +{ + vg_assert(SUCCESS); + if ((Word)RES != -1) { + if (ARG4 != 0) + POST_MEM_WRITE( ARG4, sizeof(struct vki_kevent_freebsd11)*RES) ; + } +} +#endif + +// SYS_extattr_set_fd 371 +// ssize_t extattr_set_fd(int fd, int attrnamespace, const char *attrname, +// const void *data, size_t nbytes); +PRE(sys_extattr_set_fd) +{ + PRINT("sys_extattr_set_fd ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", SARG1,SARG2,ARG3,ARG4,ARG5); + PRE_REG_READ5(int, "extattr_set_fd", int, fd, int, attrnamespace, const char *,attrname, const void *,data, size_t, nbytes); + PRE_MEM_RASCIIZ( "extattr_set_fd(attrname)", ARG3 ); + PRE_MEM_READ("extattr_set_fd(data)", ARG4, ARG5); +} + +// SYS_extattr_get_fd 372 +// ssize_t extattr_get_fd(int fd, int attrnamespace, const char *attrname, +// void *data, size_t nbytes); +PRE(sys_extattr_get_fd) +{ + PRINT("sys_extattr_get_fd ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", SARG1,SARG2,ARG3,ARG4,ARG5); + PRE_REG_READ5(int, "extattr_get_fd", int, fd, int, attrnamespace, const char *,attrname, const void *,data, size_t, nbytes); + PRE_MEM_RASCIIZ( "extattr_get_fd(attrname)", ARG3 ); + PRE_MEM_WRITE("extattr_get_fd(data)", ARG4, ARG5); +} + +POST(sys_extattr_get_fd) +{ + POST_MEM_WRITE(ARG4, ARG5); +} + +// SYS_extattr_delete_fd 373 +// int extattr_delete_fd(int fd, int attrnamespace, const char *attrname); +PRE(sys_extattr_delete_fd) +{ + PRINT("sys_extattr_delete_fd ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1,SARG2,ARG3); + PRE_REG_READ3(int, "extattr_delete_fd", int, fd, int, attrnamespace, const char *,attrname); + PRE_MEM_RASCIIZ( "extattr_delete_fd(attrname)", ARG3 ); +} + +// SYS___setugid 374 +// no manpage? +// syscalls.master: int __setugid(int flag); +PRE(sys___setugid) +{ + PRINT("sys___setugid ( %" FMT_REGWORD "d )", SARG1); + PRE_REG_READ1(int, "__setugid", int, flag); +} + +// SYS_eaccess 376 +// int eaccess(const char *path, int mode); +PRE(sys_eaccess) +{ + PRINT("sys_eaccess ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char*)ARG1,ARG2); + PRE_REG_READ2(int, "eaccess", const char *, path, int, mode); + PRE_MEM_RASCIIZ( "eaccess(path)", ARG1 ); +} + +// SYS_afs3_syscall 377 +// @todo + +// SYS_nmount 378 +// int nmount(struct iovec *iov, u_int niov, int flags); +PRE(sys_nmount) +{ + PRINT("sys_nmount ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "d )", ARG1, ARG2, SARG3); + PRE_REG_READ3(int, "nmount", struct iovec *, iov, u_int, niov, int, flags); + PRE_MEM_READ( "nmount(pathname)", ARG1, ARG2*sizeof(struct vki_iovec) ); +} + +// SYS___mac_get_proc 384 +// @todo + +// SYS___mac_set_proc 385 +// @todo + +// SYS___mac_get_fd 386 +// @todo + +// SYS___mac_get_file 387 +// @todo + +// SYS___mac_set_fd 388 +// @todo + +// SYS___mac_set_file 389 +// @todo + +// SYS_kenv 390 +// int kenv(int action, const char *name, char *value, int len); +PRE(sys_kenv) +{ + PRINT("sys_kenv ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "kenv", + int, action, const char *, name, char *, value, int, len); + switch (ARG1) { + case VKI_KENV_GET: + case VKI_KENV_SET: + case VKI_KENV_UNSET: + PRE_MEM_RASCIIZ("kenv(name)", ARG2); + /* FALLTHROUGH */ + case VKI_KENV_DUMP: + break; + default: + VG_(dmsg)("Warning: Bad action %" FMT_REGWORD "u in kenv\n", ARG1); + } +} + +POST(sys_kenv) +{ + if (SUCCESS) { + switch (ARG1) { + case VKI_KENV_GET: + POST_MEM_WRITE(ARG3, ARG4); + break; + case VKI_KENV_DUMP: + if (ARG3 != (Addr)NULL) + POST_MEM_WRITE(ARG3, ARG4); + break; + } + } +} + +// SYS_lchflags 391 +// int lchflags(const char *path, unsigned long flags); +PRE(sys_lchflags) +{ + PRINT("sys_lchflags ( %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(int, "lchflags", + const char *, path, unsigned long, flags); + PRE_MEM_RASCIIZ( "lchflags(path)", ARG1 ); +} + +// SYS_uuidgen 392 +// int uuidgen(struct uuid *store, int count); +PRE(sys_uuidgen) +{ + PRINT("sys_uuidgen ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2); + PRE_REG_READ2(int, "uuidgen", + struct vki_uuid *, store, int, count); + PRE_MEM_WRITE( "uuidgen(store)", ARG1, ARG2 * sizeof(struct vki_uuid)); +} + +POST(sys_uuidgen) +{ + if (SUCCESS) + POST_MEM_WRITE( ARG1, ARG2 * sizeof(struct vki_uuid) ); +} + +// SYS_sendfile 393 +// x86/amd64 + +// SYS_mac_syscall 394 +// @todo + +#if (FREEBSD_VERS >= FREEBSD_12) + +// SYS_freebsd11_getfsstat 395 +// int getfsstat(struct freebsd11_statfs *buf, long bufsize, int mode); + +PRE(sys_freebsd11_getfsstat) +{ + PRINT("sys_freebsd11_getfsstat ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "getfsstat", struct vki_freebsd11_statfs *, buf, long, bufsize, int, mode); + PRE_MEM_WRITE( "getfsstat(buf)", ARG1, ARG2 ); +} + +POST(sys_freebsd11_getfsstat) +{ + vg_assert(SUCCESS); + if ((Word)RES != -1) { + POST_MEM_WRITE( ARG1, RES * sizeof(struct vki_freebsd11_statfs) ); + } +} + +// SYS_freebsd11_statfs 396 +// int statfs(const char *path, struct statfs *buf); +PRE(sys_freebsd11_statfs) +{ + PRINT("sys_statfs ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(int, "statfs", const char *, path, struct statfs *, buf); + PRE_MEM_RASCIIZ( "statfs(path)", ARG1 ); + PRE_MEM_WRITE( "statfs(buf)", ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + +POST(sys_freebsd11_statfs) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + +// SYS_freebsd11_fstatfs 397 +// int fstatfs(int fd, struct statfs *buf); +PRE(sys_freebsd11_fstatfs) +{ + PRINT("sys_fstatfs ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2); + PRE_REG_READ2(int, "fstatfs", + unsigned int, fd, struct statfs *, buf); + PRE_MEM_WRITE( "fstatfs(buf)", ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + +POST(sys_freebsd11_fstatfs) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + +// SYS_freebsd11_fhstatfs 398 +// int fhstatfs(const fhandle_t *fhp, struct statfs *buf); +PRE(sys_freebsd11_fhstatfs) +{ + PRINT("sys_fhstatfs ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2); + PRE_REG_READ2(int, "fhstatfs", + struct fhandle *, fhp, struct statfs *, buf); + PRE_MEM_READ( "fhstatfs(fhp)", ARG1, sizeof(struct vki_fhandle) ); + PRE_MEM_WRITE( "fhstatfs(buf)", ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + +POST(sys_freebsd11_fhstatfs) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + + +#else + +PRE(sys_getfsstat) +{ + PRINT("sys_getfsstat ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "getfsstat", struct vki_freebsd11_statfs *, buf, long, bufsize, int, mode); + PRE_MEM_WRITE( "getfsstat(buf)", ARG1, ARG2 ); +} + +POST(sys_getfsstat) +{ + vg_assert(SUCCESS); + if ((Word)RES != -1) { + POST_MEM_WRITE( ARG1, RES * sizeof(struct vki_freebsd11_statfs) ); + } +} + +PRE(sys_statfs) +{ + PRINT("sys_statfs ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(int, "statfs", const char *, path, struct statfs *, buf); + PRE_MEM_RASCIIZ( "statfs(path)", ARG1 ); + PRE_MEM_WRITE( "statfs(buf)", ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + +POST(sys_statfs) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + +PRE(sys_fstatfs) +{ + PRINT("sys_fstatfs ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2); + PRE_REG_READ2(int, "fstatfs", + unsigned int, fd, struct statfs *, buf); + PRE_MEM_WRITE( "fstatfs(buf)", ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + +POST(sys_fstatfs) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + +PRE(sys_fhstatfs) +{ + PRINT("sys_fhstatfs ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2); + PRE_REG_READ2(int, "fhstatfs", + struct fhandle *, fhp, struct statfs *, buf); + PRE_MEM_READ( "fhstatfs(fhp)", ARG1, sizeof(struct vki_fhandle) ); + PRE_MEM_WRITE( "fhstatfs(buf)", ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + +POST(sys_fhstatfs) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) ); +} + + +#endif + +// SYS_ksem_close 400 +// @todo + +// SYS_ksem_post 401 +// @todo + +// SYS_ksem_wait 402 +// @todo + +// SYS_ksem_trywait 403 +// @todo + +// SYS_ksem_init 404 +// @todo + +// SYS_ksem_open 405 +// @todo + +// SYS_ksem_unlink 406 +// @todo + +// SYS_ksem_getvalue 407 +// @todo + +// SYS_ksem_destroy 408 +// @todo + +// SYS___mac_get_pid 409 +// @todo + +// SYS___mac_get_link 410 +// @todo + +// SYS___mac_set_link 411 +// @todo + +// SYS_extattr_set_link 412 +// ssize_t extattr_set_link(const char *path, int attrnamespace, +// const char *attrname, const void *data, size_t nbytes); +PRE(sys_extattr_set_link) +{ + PRINT("sys_extattr_set_link ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,SARG2,ARG3,ARG4,ARG5); + PRE_REG_READ5(ssize_t, "extattr_set_link", + const char *, path, int, attrnamespace, const char *, attrname, const void *, data, size_t, nbytes); + PRE_MEM_RASCIIZ("extattr_set_link(path)", ARG1); + PRE_MEM_RASCIIZ("extattr_set_link(attrname)", ARG3); + PRE_MEM_READ("extattr_set_link(data)", ARG4, ARG5); +} + +// SYS_extattr_get_link 413 +// ssize_t extattr_get_link(const char *path, int attrnamespace, +// const char *attrname, void *data, size_t nbytes); +PRE(sys_extattr_get_link) +{ + PRINT("sys_extattr_get_link ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,SARG2,ARG3,ARG4,ARG5); + PRE_REG_READ5(ssize_t, "extattr_get_link", + const char *, path, int, attrnamespace, const char *, attrname, void *, data, size_t, nbytes); + PRE_MEM_RASCIIZ("extattr_get_link(path)", ARG1); + PRE_MEM_RASCIIZ("extattr_get_link(attrname)", ARG3); + if (ARG4) { + PRE_MEM_WRITE("extattr_get_link(data)", ARG4, ARG5); + } +} + +POST(sys_extattr_get_link) +{ + if (ARG4) { + POST_MEM_WRITE(ARG4, ARG5); + } +} + +// SYS_extattr_delete_link 414 +// int extattr_delete_link(const char *path, int attrnamespace, +// const char *attrname); +PRE(sys_extattr_delete_link) +{ + PRINT("sys_extattr_delete_link ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", ARG1,SARG2,ARG3); + PRE_REG_READ3(ssize_t, "extattr_delete_link", + const char *, path, int, attrnamespace, const char *, attrname); + PRE_MEM_RASCIIZ("extattr_delete_link(path)", ARG1); + PRE_MEM_RASCIIZ("extattr_delete_link(attrname)", ARG3); +} + +// SYS___mac_execve 415 +// @todo + +// SYS_sigaction 416 +//int sigaction(int sig, const struct sigaction * restrict act, +// struct sigaction * restrict oact); +PRE(sys_sigaction) +{ + vki_sigaction_toK_t new, *newp; + vki_sigaction_fromK_t old, *oldp; + + PRINT("sys_sigaction ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + SARG1,ARG2,ARG3); + PRE_REG_READ3(long, "sigaction", + int, sign, const struct sigaction *, act, + struct sigaction *, oact); + + newp = oldp = NULL; + + if (ARG2 != 0) { + struct vki_sigaction *sa = (struct vki_sigaction *)ARG2; + PRE_MEM_READ( "sigaction(act->sa_handler)", (Addr)&sa->ksa_handler, sizeof(sa->ksa_handler)); + PRE_MEM_READ( "sigaction(act->sa_mask)", (Addr)&sa->sa_mask, sizeof(sa->sa_mask)); + PRE_MEM_READ( "sigaction(act->sa_flags)", (Addr)&sa->sa_flags, sizeof(sa->sa_flags)); + } + + if (ARG3 != 0) { + PRE_MEM_WRITE( "sigaction(oact)", ARG3, sizeof(struct vki_sigaction)); + oldp = &old; + } + + if (ARG2 != 0 + && ! ML_(safe_to_deref)((void *)(Addr)ARG2, + sizeof(struct vki_sigaction))) { + VG_(umsg)("Warning: bad act handler address %p in sigaction()\n", + (void *)(Addr)ARG2); + SET_STATUS_Failure ( VKI_EFAULT ); + } else if ((ARG3 != 0 + && ! ML_(safe_to_deref)((void *)(Addr)ARG3, + sizeof(struct vki_sigaction)))) { + VG_(umsg)("Warning: bad oact handler address %p in sigaction()\n", + (void *)(Addr)ARG3); + SET_STATUS_Failure ( VKI_EFAULT ); + } else { + if (ARG2 != 0) { + struct vki_sigaction *oldnew = + (struct vki_sigaction *)(Addr)ARG2; + + new.ksa_handler = oldnew->ksa_handler; + new.sa_flags = oldnew->sa_flags; + new.sa_mask = oldnew->sa_mask; + newp = &new; + } + + SET_STATUS_from_SysRes( VG_(do_sys_sigaction)(ARG1, newp, oldp) ); + + if (ARG3 != 0 && SUCCESS && RES == 0) { + struct vki_sigaction *oldold = + (struct vki_sigaction *)(Addr)ARG3; + + oldold->ksa_handler = oldp->ksa_handler; + oldold->sa_flags = oldp->sa_flags; + oldold->sa_mask = oldp->sa_mask; + } + } +} + +POST(sys_sigaction) +{ + vg_assert(SUCCESS); + if (RES == 0 && ARG3 != 0) + POST_MEM_WRITE( ARG3, sizeof(struct vki_sigaction)); +} + +// SYS_sigreturn 417 +// x86/amd64 + +// SYS_getcontext 421 +// SYS_setcontext 422 +// SYS_swapcontext 423 +// PRE in x86/amd64 + +POST(sys_getcontext) +{ + POST_MEM_WRITE( ARG1, sizeof(struct vki_ucontext) ); +} + +POST(sys_swapcontext) +{ + if (SUCCESS) + POST_MEM_WRITE( ARG1, sizeof(struct vki_ucontext) ); +} + +// SYS_swapoff 424 +// int swapoff(const char *special); +PRE(sys_swapoff) +{ + PRINT("sys_swapoff ( %#" FMT_REGWORD "x(%s) )", ARG1,(char *)ARG1); + PRE_REG_READ1(int, "swapoff", const char *, special); + PRE_MEM_RASCIIZ( "swapoff(special)", ARG1 ); +} + +// SYS___acl_get_link 425 +// int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp); +PRE(sys___acl_get_link) +{ + PRINT("sys___acl_get_link ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "__acl_get_link", + const char *, path, int, acltype, struct vki_acl *, aclp); + PRE_MEM_RASCIIZ( "__acl_get_link(path)", ARG1 ); + PRE_MEM_WRITE( "__acl_get_link(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +POST(sys___acl_get_link) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG3, sizeof(struct vki_acl) ); + } +} + +// SYS___acl_set_link 426 +// int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp); +PRE(sys___acl_set_link) +{ + PRINT("sys___acl_set_link ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "__acl_set_link", + const char *, path, int, acltype, struct vki_acl *, aclp); + PRE_MEM_RASCIIZ( "__acl_set_link(path)", ARG1 ); + PRE_MEM_READ( "__acl_set_link(aclp)", ARG3, sizeof(struct vki_acl) ); +} +// SYS___acl_delete_link 427 +// int __acl_delete_link(const char *path, acl_type_t type); +PRE(sys___acl_delete_link) +{ + PRINT("sys___acl_delete_link ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG2); + PRE_MEM_RASCIIZ( "__acl_delete_link(path)", ARG1 ); + PRE_REG_READ2(int, "__acl_delete_link", + const char *, path, int, acltype); +} + +// SYS___acl_aclcheck_link 428 +// int __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp); +PRE(sys___acl_aclcheck_link) +{ + PRINT("sys___acl_aclcheck_link ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "__acl_aclcheck_link", + const char *, path, int, acltype, struct vki_acl *, aclp); + PRE_MEM_RASCIIZ( "__acl_check_link(path)", ARG1 ); + PRE_MEM_READ( "__acl_aclcheck_link(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +// SYS_sigwait 429 +// int sigwait(const sigset_t * restrict set, int * restrict sig); +PRE(sys_sigwait) +{ + *flags |= SfMayBlock; + PRINT("sys_sigwait ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + ARG1,ARG2); + PRE_REG_READ2(int, "sigwait", + const vki_sigset_t *, set, int *, sig); + if (ARG1 != 0) + PRE_MEM_READ( "sigwait(set)", ARG1, sizeof(vki_sigset_t)); + if (ARG2 != 0) + PRE_MEM_WRITE( "sigwait(sig)", ARG2, sizeof(int)); +} + +POST(sys_sigwait) +{ + if (ARG2 != 0) + POST_MEM_WRITE( ARG2, sizeof(int)); +} + +// SYS_thr_create 430 +// no manpage? +// syscalls.master: int thr_create(_In_ ucontext_t *ctx, _Out_ long *id, int flags ); +PRE(sys_thr_create) +{ + PRINT( "sys_thr_create ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )", ARG1, ARG2, SARG3 ); + PRE_REG_READ3(int, "thr_create", /*ucontext_t*/void *, ctx, long *, id, int, flags ); + + VG_(message)(Vg_UserMsg, "thr_create() not implemented"); + VG_(unimplemented)("Valgrind does not support thr_create()."); + + SET_STATUS_Failure(VKI_ENOSYS); +} + +// SYS_thr_exit 431 +// void thr_exit(long *state); +PRE(sys_thr_exit) +{ + ThreadState *tst; + + PRINT( "sys_thr_exit ( %#" FMT_REGWORD "x )", ARG1 ); + PRE_REG_READ1(void, "thr_exit", long *, state); + + if (ARG1) { + PRE_MEM_WRITE( "thr_exit(state)", ARG1, sizeof(long) ); + } + + tst = VG_(get_ThreadState)(tid); + tst->exitreason = VgSrc_ExitThread; + tst->os_state.exitcode = ARG1; + SET_STATUS_Success(0); +} + +// SYS_thr_self 432 +// int thr_self(long *id); +PRE(sys_thr_self) +{ + PRINT( "sys_thr_self ( %#" FMT_REGWORD "x )", ARG1 ); + PRE_REG_READ1(int, "thr_self", long *, id); + PRE_MEM_WRITE( "thr_self()", ARG1, sizeof(long)); +} + +POST(sys_thr_self) +{ + POST_MEM_WRITE( ARG1, sizeof(long)); +} + +// SYS_thr_kill 433 +// int thr_kill(long id, int sig); +PRE(sys_thr_kill) +{ + PRINT("sys_thr_kill ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG2); + PRE_REG_READ2(long, "thr_kill", long, id, int, sig); + if (!ML_(client_signal_OK)(ARG2)) { + SET_STATUS_Failure( VKI_EINVAL ); + return; + } + + /* Check to see if this kill gave us a pending signal */ + *flags |= SfPollAfter; + + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "thr_kill: sending signal %lu to tid %lu\n", + ARG2, ARG1); + + /* If we're sending SIGKILL, check to see if the target is one of + our threads and handle it specially. */ + if (ARG2 == VKI_SIGKILL && ML_(do_sigkill)(ARG1, -1)) { + SET_STATUS_Success(0); + return; + } + + /* Ask to handle this syscall via the slow route, since that's the + only one that sets tst->status to VgTs_WaitSys. If the result + of doing the syscall is an immediate run of + async_signalhandler() in m_signals, then we need the thread to + be properly tidied away. I have the impression the previous + version of this wrapper worked on x86/amd64 only because the + kernel did not immediately deliver the async signal to this + thread (on ppc it did, which broke the assertion re tst->status + at the top of async_signalhandler()). */ + *flags |= SfMayBlock; +} + +POST(sys_thr_kill) +{ + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "thr_kill: sent signal %lu to tid %lu\n", + ARG2, ARG1); +} + +#if (FREEBSD_VERS <= FREEBSD_10) +// SYS__umtx_lock 434 +PRE(sys__umtx_lock) +{ + PRINT( "sys__umtx_lock ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(long, "_umtx_lock", struct vki_umtx *, umtx); + PRE_MEM_READ( "_umtx_lock(mtx)", ARG1, sizeof(struct vki_umtx) ); + PRE_MEM_WRITE( "_umtx_lock(mtx)", ARG1, sizeof(struct vki_umtx) ); +} + +POST(sys__umtx_lock) +{ + if (SUCCESS) + POST_MEM_WRITE(ARG1, sizeof(struct vki_umtx)); +} + +// SYS__umtx_unlock 434 +PRE(sys__umtx_unlock) +{ + PRINT( "sys__umtx_unlock ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(long, "_umtx_unlock", struct vki_umtx *, umtx); + PRE_MEM_READ( "_umtx_unlock(mtx)", ARG1, sizeof(struct vki_umtx) ); + PRE_MEM_WRITE( "_umtx_unlock(mtx)", ARG1, sizeof(struct vki_umtx) ); +} + +POST(sys__umtx_unlock) +{ + if (SUCCESS) + POST_MEM_WRITE(ARG1, sizeof(struct vki_umtx)); +} +#endif + +// SYS_jail_attach 436 +// int jail_attach(int jid); +PRE(sys_jail_attach) +{ + PRINT("sys_jail_attach ( %" FMT_REGWORD "d )", SARG1); + PRE_REG_READ1(int, "jail_attach", int, jid); +} + +// SYS_extattr_list_fd 437 +// ssize_t extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes); +PRE(sys_extattr_list_fd) +{ + PRINT("extattr_list_fd ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", SARG1, SARG2, ARG3, ARG4); + PRE_REG_READ4(ssize_t, "extattr_list_fd", int, id, int, attrnamespace, void *,data, size_t, nbytes); + PRE_MEM_WRITE("extattr_list_fd(data)", ARG3, ARG4); +} + +POST(sys_extattr_list_fd) +{ + POST_MEM_WRITE(ARG3, ARG4); +} + +// SYS_extattr_list_file 438 +// ssize_t extattr_list_file(const char *path, int attrnamespace, void *data, +// size_t nbytes); +PRE(sys_extattr_list_file) +{ + PRINT("extattr_list_file ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, SARG2, ARG3, ARG4); + PRE_REG_READ4(ssize_t, "extattr_list_file", const char *, path, int, attrnamespace, void *,data, size_t, nbytes); + PRE_MEM_RASCIIZ("extattr_list_file(path)", ARG1); + PRE_MEM_WRITE("extattr_list_file(data)", ARG3, ARG4); +} + +POST(sys_extattr_list_file) +{ + POST_MEM_WRITE(ARG3, ARG4); +} + +// SYS_extattr_list_link 439 +// ssize_t extattr_get_link(const char *path, int attrnamespace, +// const char *attrname, void *data, size_t nbytes); +PRE(sys_extattr_list_link) +{ + PRINT("extattr_list_link ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, SARG2, ARG3, ARG4); + PRE_REG_READ4(ssize_t, "extattr_list_link", const char *, path, int, attrnamespace, void *,data, size_t, nbytes); + PRE_MEM_RASCIIZ("extattr_list_link(path)", ARG1); + PRE_MEM_WRITE("extattr_list_link(data)", ARG3, ARG4); +} + +POST(sys_extattr_list_link) +{ + POST_MEM_WRITE(ARG3, ARG4); +} + +// SYS_ksem_timedwait 441 +// @todo + +// SYS_thr_suspend 442 +// int thr_suspend(struct timespec *timeout); +PRE(sys_thr_suspend) +{ + PRINT("sys_thr_suspend ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "thr_suspend", struct timespec *, timeout); + PRE_MEM_READ("thr_suspend(timeout)", ARG1, sizeof(struct vki_timespec)); + + VG_(message)(Vg_UserMsg, "thr_supend() not implemented"); + VG_(unimplemented)("Valgrind does not support thr_suspend()."); + + SET_STATUS_Failure(VKI_ENOSYS); +} + +// SYS_thr_wake 443 +// int thr_wake(long id); +PRE(sys_thr_wake) +{ + PRINT("sys_thr_wake ( %" FMT_REGWORD "d )", SARG1); + PRE_REG_READ1(long, "thr_wake", long, id); + /* + if (VG_(is_valid_tid)(ARG1)) { + VG_(threads)[ARG1].status = VgTs_Runnable; + } else { + SET_STATUS_Failure( VKI_ESRCH ); + } + */ +} + +// SYS_kldunloadf 444 +// int kldunloadf(int fileid, int flags); +PRE(sys_kldunloadf) +{ + PRINT("sys_kldunloadf ( %" FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1, SARG2); + PRE_REG_READ2(int, "kldunloadf", int, fileid, int, flags); +} + +// SYS_audit 445 +// int audit(const char *record, u_int length); +// @todo + +// SYS_auditon 446 +// int auditon(int cmd, void *data, u_int length); +// @todo + +// SYS_getauid 447 +// int getauid(au_id_t *auid); +// @todo + +// SYS_setauid 448 +// int setauid(au_id_t *auid); +// @todo + +// SYS_getaudit 449 +// int getaudit(auditinfo_t *auditinfo); +// @todo + +// SYS_setaudit 450 +// int setaudit(auditinfo_t *auditinfo); +// @todo + +// SYS_getaudit_addr 451 +// int getaudit_addr(auditinfo_addr_t *auditinfo_addr, u_int length); +// @todo + +// SYS_setaudit_addr 452 +// int setaudit_addr(auditinfo_addr_t *auditinfo_addr, u_int length); +// @todo + +// SYS_auditctl 453 +// @todo + +// SYS__umtx_op 454 +// int _umtx_op(void *obj, int op, u_long val, void *uaddr, void *uaddr2); +PRE(sys__umtx_op) +{ + /* 5 args are always passed through. The last two can vary, but + they're always pointers. They may not be used though. */ + switch(ARG2) { + case VKI_UMTX_OP_LOCK: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, LOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_lock", + struct umtx *, obj, int, op, unsigned long, id, + size_t, timeout_size, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_lock(mtx)", ARG1, sizeof(struct vki_umtx) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_lock(timespec)", ARG5, ARG4 ); + PRE_MEM_WRITE( "_umtx_op_lock(mtx)", ARG1, sizeof(struct vki_umtx) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_UNLOCK: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, UNLOCK, %" FMT_REGWORD "u)", ARG1, ARG3); + PRE_REG_READ3(long, "_umtx_op_unlock", + struct umtx *, obj, int, op, unsigned long, id); + PRE_MEM_READ( "_umtx_op_unlock(mtx)", ARG1, sizeof(struct vki_umtx) ); + PRE_MEM_WRITE( "_umtx_op_unlock(mtx)", ARG1, sizeof(struct vki_umtx) ); + break; + case VKI_UMTX_OP_WAIT: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, WAIT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_wait", + long *, obj, int, op, unsigned long, val, + size_t, timeout_size, struct vki_timespec *, timeout); + if (ARG1) { + PRE_MEM_READ( "_umtx_op_wait(val)", ARG1, sizeof(long) ); + if (*(long*)ARG1 == (long)ARG3) { + *flags |= SfMayBlock; + } + } + + if (ARG5) { + PRE_MEM_READ( "_umtx_op_wait(timeout)", ARG5, ARG4 ); + } + + break; + case VKI_UMTX_OP_WAKE: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, WAKE, %" FMT_REGWORD "u)", ARG1, ARG3); + PRE_REG_READ3(long, "_umtx_op_wake", + struct umtx *, obj, int, op, unsigned long, val); + PRE_MEM_READ( "_umtx_op_wake(mtx)", ARG1, sizeof(struct vki_umtx) ); + break; + case VKI_UMTX_OP_MUTEX_TRYLOCK: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, MUTEX_TRYLOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_mutex_trylock", + struct umutex *, obj, int, op, unsigned long, noid, + size_t, timeout_size, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_mutex_trylock(mutex)", ARG1, sizeof(struct vki_umutex) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_mutex_trylock(timespec)", ARG5, ARG4 ); + PRE_MEM_WRITE( "_umtx_op_mutex_trylock(mutex)", ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_MUTEX_LOCK: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, MUTEX_LOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_mutex_lock", + struct umutex *, obj, int, op, unsigned long, noid, + size_t, timeout_size, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_mutex_lock(mutex)", ARG1, sizeof(struct vki_umutex) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_mutex_lock(timespec)", ARG5, ARG4 ); + PRE_MEM_WRITE( "_umtx_op_mutex_lock(mutex)", ARG1, sizeof(struct vki_umutex) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_MUTEX_UNLOCK: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, MUTEX_UNLOCK)", ARG1); + PRE_REG_READ2(long, "_umtx_op_mutex_unlock", + struct umutex *, obj, int, op); + PRE_MEM_READ( "_umtx_op_mutex_unlock(mutex)", ARG1, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_mutex_unlock(mutex)", ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_SET_CEILING: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, SET_CEILING, %" FMT_REGWORD "u, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4); + PRE_REG_READ4(long, "_umtx_op_set_ceiling", + struct umutex *, obj, int, op, unsigned int, ceiling, + unsigned int *, old_ceiling); + PRE_MEM_READ( "_umtx_op_set_ceiling(mutex)", ARG1, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_set_ceiling(mutex)", ARG1, sizeof(struct vki_umutex) ); + if (ARG4) + PRE_MEM_WRITE( "_umtx_op_set_ceiling(old_ceiling)", ARG4, sizeof(vki_uint32_t) ); + break; + case VKI_UMTX_OP_CV_WAIT: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, CV_WAIT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_cv_wait", + struct ucond *, obj, int, op, unsigned long, wflags, + struct umutex *, umtx, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_cv_wait(cond)", ARG1, sizeof(struct vki_ucond) ); + PRE_MEM_WRITE( "_umtx_op_cv_wait(cond)", ARG1, sizeof(struct vki_ucond) ); + PRE_MEM_READ( "_umtx_op_cv_wait(mutex)", ARG4, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_cv_wait(mutex)", ARG4, sizeof(struct vki_umutex) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_cv_wait(timespec)", ARG5, sizeof(struct vki_timespec) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_CV_SIGNAL: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, CV_SIGNAL)", ARG1); + PRE_REG_READ2(long, "_umtx_op_cv_signal", + struct ucond *, obj, int, op); + PRE_MEM_READ( "_umtx_op_cv_signal(cond)", ARG1, sizeof(struct vki_ucond) ); + PRE_MEM_WRITE( "_umtx_op_cv_signal(cond)", ARG1, sizeof(struct vki_ucond) ); + break; + case VKI_UMTX_OP_CV_BROADCAST: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, CV_BROADCAST, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ2(long, "_umtx_op_cv_broadcast", + struct ucond *, obj, int, op); + PRE_MEM_READ( "_umtx_op_cv_broadcast(cond)", ARG1, sizeof(struct vki_ucond) ); + PRE_MEM_WRITE( "_umtx_op_cv_broadcast(cond)", ARG1, sizeof(struct vki_ucond) ); + break; + case VKI_UMTX_OP_WAIT_UINT: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, CV_WAIT_UINT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_wait_uint", + int *, obj, int, op, unsigned long, id, + size_t, timeout_wait, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_wait(uint)", ARG1, sizeof(int) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_wait(timespec)", ARG5, ARG4 ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_RW_RDLOCK: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, RW_RDLOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_rw_rdlock", + struct urwlock *, obj, int, op, unsigned long, noid, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_rw_rdlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + PRE_MEM_WRITE( "_umtx_op_rw_rdlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_RW_WRLOCK: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, RW_WRLOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_rw_wrlock", + struct urwlock *, obj, int, op, unsigned long, noid, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_rw_wrlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + PRE_MEM_WRITE( "_umtx_op_rw_wrlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_RW_UNLOCK: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, RW_UNLOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ2(long, "_umtx_op_rw_unlock", + struct urwlock *, obj, int, op); + PRE_MEM_READ( "_umtx_op_rw_unlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + PRE_MEM_WRITE( "_umtx_op_rw_unlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + break; + case VKI_UMTX_OP_WAIT_UINT_PRIVATE: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, CV_WAIT_UINT_PRIVATE, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_wait_uint_private", + int *, obj, int, op, unsigned long, id, + size_t, timeout_size, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_wait_private(uint)", ARG1, sizeof(int) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_wait_private(umtx_time)", ARG5, ARG4 ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_WAKE_PRIVATE: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, CV_WAKE_PRIVATE, %" FMT_REGWORD "u)", ARG1, ARG3); + PRE_REG_READ3(long, "_umtx_op_wake_private", + struct umtx *, obj, int, op, unsigned long, id); + PRE_MEM_READ( "_umtx_op_wake_private(mtx)", ARG1, sizeof(struct vki_umtx) ); + break; + case VKI_UMTX_OP_MUTEX_WAIT: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, MUTEX_WAIT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ2(long, "_umtx_op_mutex_wait", + struct umutex *, obj, int, op); + PRE_MEM_READ( "_umtx_op_mutex_wait(mutex)", ARG1, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_mutex_wait(mutex)", ARG1, sizeof(struct vki_umutex) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_MUTEX_WAKE: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, MUTEX_WAKE, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ2(long, "_umtx_op_mutex_wake", + struct umutex *, obj, int, op); + PRE_MEM_READ( "_umtx_op_mutex_wake(mutex)", ARG1, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_mutex_wake(mutex)", ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_SEM_WAIT: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, SEM_WAIT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_sem_wait", + struct usem *, obj, int, op, unsigned long, id, + size_t, timeout_size, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_sem_wait(usem)", ARG1, sizeof(struct vki_usem) ); + PRE_MEM_WRITE( "_umtx_op_sem_wait(usem)", ARG1, sizeof(struct vki_usem) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_sem_wait(umtx_time)", ARG5, ARG4 ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_SEM_WAKE: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, SEM_WAKE, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ2(long, "_umtx_op_sem_wake", + struct umutex *, obj, int, op); + PRE_MEM_READ( "_umtx_op_sem_wake(mutex)", ARG1, sizeof(struct vki_usem) ); + PRE_MEM_WRITE( "_umtx_op_sem_wake(mutex)", ARG1, sizeof(struct vki_usem) ); + break; + case VKI_UMTX_OP_NWAKE_PRIVATE: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, NWAKE_PRIVATE, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ3(long, "_umtx_op_nwake_private", + struct umutex *, obj, int, op, int, count); + PRE_MEM_READ( "_umtx_op_nwake_private(mtxs)", ARG1, ARG3 * sizeof(void *) ); + PRE_MEM_WRITE( "_umtx_op_mutex_wake(mtxs)", ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_MUTEX_WAKE2: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, MUTEX_WAKE2, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ3(long, "_umtx_op_mutex_wake2", + struct umutex *, obj, int, op, unsigned long, flags); + PRE_MEM_READ( "_umtx_op_mutex_wake(mutex)", ARG1, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_mutex_wake(mutex)", ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_SEM2_WAIT: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, SEM2_WAIT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ3(long, "_umtx_op_sem2_wake", + struct _usem2 *, obj, int, op, unsigned long, flags); + PRE_MEM_READ( "_umtx_op_sem2_wait(mutex)", ARG1, sizeof(struct vki_usem2) ); + PRE_MEM_WRITE( "_umtx_op_sem2_wait(mutex)", ARG1, sizeof(struct vki_usem2) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_SEM2_WAKE: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, SEM2_WAKE, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ3(long, "_umtx_op_sem2_wake", + struct _usem2 *, obj, int, op, unsigned long, flags); + PRE_MEM_READ( "_umtx_op_sem2_wait(mutex)", ARG1, sizeof(struct vki_usem2) ); + PRE_MEM_WRITE( "_umtx_op_sem2_wait(mutex)", ARG1, sizeof(struct vki_usem2) ); + break; + case VKI_UMTX_OP_SHM: + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, SHM, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ4(long, "_umtx_op_shm", + void *, obj, int, op, unsigned long, val, void*, uaddr); + break; + case VKI_UMTX_OP_ROBUST_LISTS: + // val (ARG2) ought to be the same as sizeof(struct vki_umtx_robust_lists_params) + // then the structure contains a pointer to mutex structures + if (ARG1 != sizeof(struct vki_umtx_robust_lists_params)) + SET_STATUS_Failure( VKI_ENOSYS ); + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, ROBUST_LISTS, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ3(long, "_umtx_op_robust_lists", + struct umtx_robust_lists_params *, obj, int, op, unsigned long, flags); + PRE_MEM_READ( "_umtx_op_robust_lists(mutex)", ARG3, sizeof(struct vki_umtx_robust_lists_params) ); + break; + default: + VG_(umsg)("WARNING: _umtx_op unsupported value.\n"); + PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u(UNKNOWN), %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2, ARG3, ARG4, ARG5); + break; + } +} + +POST(sys__umtx_op) +{ + switch(ARG2) { + case VKI_UMTX_OP_LOCK: + if (SUCCESS) + POST_MEM_WRITE( ARG1, sizeof(struct vki_umtx) ); + break; + case VKI_UMTX_OP_UNLOCK: + if (SUCCESS) + POST_MEM_WRITE( ARG1, sizeof(struct vki_umtx) ); + break; + case VKI_UMTX_OP_WAIT: + case VKI_UMTX_OP_WAKE: + case VKI_UMTX_OP_WAIT_UINT: + case VKI_UMTX_OP_WAIT_UINT_PRIVATE: + case VKI_UMTX_OP_WAKE_PRIVATE: + break; + case VKI_UMTX_OP_MUTEX_TRYLOCK: + case VKI_UMTX_OP_MUTEX_LOCK: + case VKI_UMTX_OP_MUTEX_UNLOCK: + case VKI_UMTX_OP_MUTEX_WAIT: /* Sets/clears contested bits */ + case VKI_UMTX_OP_MUTEX_WAKE: /* Sets/clears contested bits */ + if (SUCCESS) + POST_MEM_WRITE( ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_SET_CEILING: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_umutex) ); + if (ARG4) + POST_MEM_WRITE( ARG4, sizeof(vki_uint32_t) ); + } + break; + case VKI_UMTX_OP_CV_WAIT: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_ucond) ); + POST_MEM_WRITE( ARG4, sizeof(struct vki_umutex) ); + } + break; + case VKI_UMTX_OP_CV_SIGNAL: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_ucond) ); + } + break; + case VKI_UMTX_OP_CV_BROADCAST: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_ucond) ); + } + break; + case VKI_UMTX_OP_RW_RDLOCK: + case VKI_UMTX_OP_RW_WRLOCK: + case VKI_UMTX_OP_RW_UNLOCK: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_urwlock) ); + } + break; + case VKI_UMTX_OP_SEM2_WAIT: + case VKI_UMTX_OP_SEM2_WAKE: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_usem2) ); + } + break; + case VKI_UMTX_OP_SHM: + case VKI_UMTX_OP_ROBUST_LISTS: + default: + break; + } +} + +// SYS_thr_new 455 +// x86/amd64 + +// SYS_sigqueue 456 +// int sigqueue(pid_t pid, int signo, const union sigval value); +PRE(sys_sigqueue) +{ + PRINT("sys_sigqueue ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", + SARG1,SARG2,ARG3); + PRE_REG_READ3(int, "sigqueue", vki_pid_t, pid, int, signo, const union vki_sigval, value); +} + +// SYS_kmq_open 457 +// mqd_t mq_open(const char *name, int oflag, ...); +// int kmq_open(_In_z_ const char *path, int flags, mode_t mode, _In_opt_ const struct mq_attr *attr); +PRE(sys_kmq_open) +{ + if (ARG2 & VKI_O_CREAT) { + PRINT("sys_kmq_open( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %hu, %#" FMT_REGWORD "x )", + ARG1,(char *)ARG1,ARG2,(vki_mode_t)ARG3,ARG4); + PRE_REG_READ4(long, "mq_open", + const char *, name, int, oflag, vki_mode_t, mode, + struct mq_attr *, attr); + } else { + PRINT("sys_kmq_open( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %hu)", + ARG1,(char *)ARG1,ARG2,(vki_mode_t)ARG3); + PRE_REG_READ3(long, "mq_open", + const char *, name, int, oflag, vki_mode_t, mode); + } + PRE_MEM_RASCIIZ( "mq_open(name)", ARG1 ); + if (ARG2 & VKI_O_CREAT) { + PRE_MEM_READ("mq_open(attr)", ARG4, sizeof(struct vki_mq_attr)); + if (ML_(safe_to_deref)((struct vki_mq_attr *)ARG4, sizeof(struct vki_mq_attr))) { + const struct vki_mq_attr *attr = (struct vki_mq_attr *)ARG4; + PRE_MEM_READ("mq_open(attr->mq_maxmsg)", + (Addr)&attr->mq_maxmsg, sizeof(attr->mq_maxmsg) ); + PRE_MEM_READ("mq_open(attr->mq_msgsize)", + (Addr)&attr->mq_msgsize, sizeof(attr->mq_msgsize) ); + } + } +} + +POST(sys_kmq_open) +{ + vg_assert(SUCCESS); + if (!ML_(fd_allowed)(RES, "mq_open", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_with_given_name)(tid, RES, (const HChar*)ARG1); + } +} + +// SYS_kmq_setattr 458 +// int mq_setattr(mqd_t mqdes, const struct mq_attr *restrict mqstat, +// struct mq_attr *restrict omqstat); +PRE(sys_kmq_setattr) +{ + PRINT("sys_kmq_getattr( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3 ); + PRE_REG_READ3(int, "mq_setattr", + vki_mqd_t, mqdes, const struct mq_attr *, mqstat, + struct mq_attr *, omqstat); + if (!ML_(fd_allowed)(ARG1, "mq_getattr", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } else { + if (ML_(safe_to_deref)((struct vki_mq_attr *)ARG2, sizeof(struct vki_mq_attr))) { + const struct vki_mq_attr *attr = (struct vki_mq_attr *)ARG2; + PRE_MEM_READ( "mq_setattr(mqstat->mq_flags)", + (Addr)&attr->mq_flags, sizeof(attr->mq_flags) ); + } + PRE_MEM_WRITE( "mq_setattr(omqstat)", ARG3, + sizeof(struct vki_mq_attr) ); + } +} + +// SYS_kmq_timedreceive 459 +// ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, +// unsigned *msg_prio, const struct timespec *abs_timeout); +PRE(sys_kmq_timedreceive) +{ + *flags |= SfMayBlock; + PRINT("sys_kmq_timedreceive( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %llu, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + ARG1,ARG2,(ULong)ARG3,ARG4,ARG5); + PRE_REG_READ5(ssize_t, "mq_timedreceive", + vki_mqd_t, mqdes, char *, msg_ptr, vki_size_t, msg_len, + unsigned int *, msg_prio, + const struct timespec *, abs_timeout); + if (!ML_(fd_allowed)(ARG1, "mq_timedreceive", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } else { + PRE_MEM_WRITE( "mq_timedreceive(msg_ptr)", ARG2, ARG3 ); + if (ARG4 != 0) + PRE_MEM_WRITE( "mq_timedreceive(msg_prio)", + ARG4, sizeof(unsigned int) ); + if (ARG5 != 0) + PRE_MEM_READ( "mq_timedreceive(abs_timeout)", + ARG5, sizeof(struct vki_timespec) ); + } +} + +POST(sys_kmq_timedreceive) +{ + POST_MEM_WRITE( ARG2, ARG3 ); + if (ARG4 != 0) + POST_MEM_WRITE( ARG4, sizeof(unsigned int) ); +} + +// SYS_kmq_timedsend 460 +// int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, +// unsigned msg_prio, const struct timespec *abs_timeout); +PRE(sys_kmq_timedsend) +{ + *flags |= SfMayBlock; + PRINT("sys_kmq_timedsend ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", + ARG1,ARG2,(ULong)ARG3,ARG4,ARG5); + PRE_REG_READ5(int, "mq_timedsend", + vki_mqd_t, mqdes, const char *, msg_ptr, vki_size_t, msg_len, + unsigned int, msg_prio, const struct timespec *, abs_timeout); + if (!ML_(fd_allowed)(ARG1, "mq_timedsend", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } else { + PRE_MEM_READ( "mq_timedsend(msg_ptr)", ARG2, ARG3 ); + if (ARG5 != 0) + PRE_MEM_READ( "mq_timedsend(abs_timeout)", ARG5, + sizeof(struct vki_timespec) ); + } +} + +// SYS_kmq_notify 461 +// int mq_notify(mqd_t mqdes, const struct sigevent *notification); +PRE(sys_kmq_notify) +{ + PRINT("sys_kmq_notify( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2 ); + PRE_REG_READ2(int, "mq_notify", + vki_mqd_t, mqdes, const struct sigevent *, notification); + if (!ML_(fd_allowed)(ARG1, "mq_notify", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else if (ARG2 != 0) + PRE_MEM_READ( "mq_notify(notification)", + ARG2, sizeof(struct vki_sigevent) ); +} + +// SYS_kmq_unlink 462 +// int kmq_unlink(const char *path); +PRE(sys_kmq_unlink) +{ + PRINT("sys_kmq_unlink ( %#" FMT_REGWORD "x(%s) )", ARG1,(char *)ARG1); + PRE_REG_READ1(int, "mq_unlink", const char *, name); + PRE_MEM_RASCIIZ( "mq_unlink(name)", ARG1 ); +} + +// SYS_abort2 463 +// void abort2(const char *why, int nargs, void **args); +PRE(sys_abort2) +{ + PRINT( "sys_abort2 ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", ARG1, SARG2, ARG3 ); + PRE_REG_READ3(void, "abort2", const char *, why, int, nargs, void **, args); + // max length of 'why' is 128 + PRE_MEM_RASCIIZ( "abort2(why)", ARG2); + // max val for nargs is 16 + PRE_MEM_READ("abort2(args", ARG3, ARG2*sizeof(void*)); +} + +// SYS_thr_set_name 464 +// int thr_set_name(long id, const char *name); +PRE(sys_thr_set_name) +{ + PRINT( "sys_thr_set_name ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2 ); + PRE_REG_READ2(int, "thr_set_name", long, id, const char *, name); + PRE_MEM_RASCIIZ( "thr_set_name(name)", ARG2); + + if (ML_(safe_to_deref)((void*)ARG2, 1)) { + const HChar* new_name = (const HChar*) (Addr)ARG2; + ThreadState* tst = VG_(get_ThreadState)(tid); + SizeT new_len = VG_(strnlen)(new_name, VKI_MAXCOMLEN+1); + tst->thread_name = VG_(realloc)("syswrap.thr_set_name", tst->thread_name, new_len + 1); + VG_(strlcpy)(tst->thread_name, new_name, new_len + 1); + } +} + +// SYS_aio_fsync 465 +// int aio_fsync(int op, struct aiocb *iocb); +PRE(sys_aio_fsync) +{ + PRINT("aio_fsync ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1,ARG2); + PRE_REG_READ2(int, "aio_fsync", int, op, struct vki_aiocb *, iocb); + PRE_MEM_READ( "aio_fsync(iocb)", ARG2, sizeof(struct vki_aiocb) ); +} + +// SYS_rtprio_thread 466 +// int rtprio_thread(int function, lwpid_t lwpid, struct rtprio *rtp); +PRE(sys_rtprio_thread) +{ + PRINT( "sys_rtprio_thread ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2, ARG3 ); + PRE_REG_READ3(int, "rtprio_thread", + int, function, __vki_lwpid_t, lwpid, struct vki_rtprio *, rtp); + if (ARG1 == VKI_RTP_SET) { + PRE_MEM_READ( "rtprio_thread(rtp#set)", ARG3, sizeof(struct vki_rtprio)); + } else if (ARG1 == VKI_RTP_LOOKUP) { + PRE_MEM_WRITE( "rtprio_thread(rtp#lookup)", ARG3, sizeof(struct vki_rtprio)); + } else { + /* PHK ?? */ + } +} + +POST(sys_rtprio_thread) +{ + if (ARG1 == VKI_RTP_LOOKUP && RES == 0) + POST_MEM_WRITE( ARG3, sizeof(struct vki_rtprio)); +} + +// SYS_sctp_peeloff 471 +// int sctp_peeloff(int s, sctp_assoc_t id); +// @todo + +// SYS_sctp_generic_sendmsg 472 +// int sctp_generic_sendmsg(int s, void *msg, int msglen, struct sockaddr *to, +// socklen_t len, struct sctp_sndrcvinfo *sinfo, int flags); +// @tdo + + +// SYS_sctp_generic_sendmsg_iov 473 +// int sctp_generic_sendmsg_iov(int s, struct iovec *iov, int iovlen, +// struct sockaddr *to, struct sctp_sndrcvinfo *sinfo, int flags); +// @todo + +// SYS_sctp_generic_recvmsg 474 +// int sctp_generic_recvmsg(int s, struct iovec *iov, int iovlen, +// struct sockaddr *from, socklen_t *fromlen, +// struct sctp_sndrcvinfo *sinfo, int *msgflags); +// @todo + +// SYS_pread 475 +// x86/amd64 + +// SYS_pwrite 476 +// x86/amd64 + +// SYS_mmap 477 +// x86/amd64 + +// SYS_lseek 478 +// x86/amd64 + +//SYS_truncate 479 +// x86/amd64 + +// SYS_ftruncate 480 +// x86/amd64 + +// SYS_thr_kill2 481 +// int thr_kill2(pid_t pid, long id, int sig); +PRE(sys_thr_kill2) +{ + PRINT("sys_thr_kill2 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3); + PRE_REG_READ3(int, "thr_kill2", pid_t, pid, long, tid, int, sig); + if (!ML_(client_signal_OK)(ARG3)) { + SET_STATUS_Failure( VKI_EINVAL ); + return; + } + + /* Check to see if this kill gave us a pending signal */ + *flags |= SfPollAfter; + + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "thr_kill2: sending signal %lu to pid %lu/%lu\n", + ARG3, ARG1, ARG2); + + /* If we're sending SIGKILL, check to see if the target is one of + our threads and handle it specially. */ + if (ARG3 == VKI_SIGKILL && ML_(do_sigkill)(ARG2, ARG1)) { + SET_STATUS_Success(0); + return; + } + + /* Ask to handle this syscall via the slow route, since that's the + only one that sets tst->status to VgTs_WaitSys. If the result + of doing the syscall is an immediate run of + async_signalhandler() in m_signals, then we need the thread to + be properly tidied away. I have the impression the previous + version of this wrapper worked on x86/amd64 only because the + kernel did not immediately deliver the async signal to this + thread (on ppc it did, which broke the assertion re tst->status + at the top of async_signalhandler()). */ + *flags |= SfMayBlock; +} + +POST(sys_thr_kill2) +{ + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "thr_kill2: sent signal %lu to pid %lu/%lu\n", + ARG3, ARG1, ARG2); +} + +// SYS_shm_open 482 +// int shm_open(const char *path, int flags, mode_t mode); +PRE(sys_shm_open) +{ + PRE_REG_READ3(int, "shm_open", + const char *, path, int, flags, vki_mode_t, mode); + if (ARG1 == VKI_SHM_ANON) { + PRINT("sys_shm_open(%#" FMT_REGWORD "x(SHM_ANON), %" FMT_REGWORD "u, %hu)", ARG1, ARG2, (vki_mode_t)ARG3); + } else { + PRINT("sys_shm_open(%#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %hu)", ARG1, (HChar *)ARG1, ARG2, (vki_mode_t)ARG3); + PRE_MEM_RASCIIZ( "shm_open(path)", ARG1 ); + } + *flags |= SfMayBlock; +} + +POST(sys_shm_open) +{ + vg_assert(SUCCESS); + if (!ML_(fd_allowed)(RES, "shm_open", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_with_given_name)(tid, RES, (HChar*)ARG1); + } +} + +// SYS_shm_unlink 483 +// int shm_unlink(const char *path); +PRE(sys_shm_unlink) +{ + PRINT("sys_shm_unlink(%#" FMT_REGWORD "x(%s))", ARG1, (char *)ARG1); + PRE_REG_READ1(int, "shm_unlink", + const char *, path); + + PRE_MEM_RASCIIZ( "shm_unlink(path)", ARG1 ); + + *flags |= SfMayBlock; +} + +// SYS_cpuset 484 +// int cpuset(cpusetid_t *setid); +PRE(sys_cpuset) +{ + PRINT("sys_cpuset ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "cpuset", vki_cpusetid_t *, setid); + PRE_MEM_WRITE("cpuset(setid)", ARG1, sizeof(vki_cpusetid_t)); +} + +POST(sys_cpuset) +{ + POST_MEM_WRITE(ARG1, sizeof(vki_cpusetid_t)); +} + +// SYS_cpuset_setid 485 +// amd64 / x86 + +// SYS_cpuset_getid 486 +// amd64 / x86 + +// SYS_cpuset_getaffinity 487 +// amd64 / x86 + +// SYS_cpuset_setaffinity 488 +// amd64 / x86 + +// SYS_faccessat 489 +// int faccessat(int fd, const char *path, int mode, int flag); +PRE(sys_faccessat) +{ + PRINT("sys_faccessat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ3(int, "faccessat", + int, fd, const char *, path, int, flag); + PRE_MEM_RASCIIZ( "faccessat(path)", ARG2 ); +} + +// SYS_fchmodat 490 +// int fchmodat(int fd, const char *path, mode_t mode, int flag); +PRE(sys_fchmodat) +{ + PRINT("sys_fchmodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ4(int, "fchmodat", + int, fd, const char *, path, vki_mode_t, mode, int, flag); + PRE_MEM_RASCIIZ( "fchmodat(path)", ARG2 ); +} + +// SYS_fchownat 491 +// int fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag); +PRE(sys_fchownat) +{ + PRINT("sys_fchownat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x, %" FMT_REGWORD "d )", + ARG1,ARG2,(char*)ARG2,ARG3,ARG4, SARG5); + PRE_REG_READ5(int, "fchownat", + int, fd, const char *, path, + vki_uid_t, owner, vki_gid_t, group, int, flag); + PRE_MEM_RASCIIZ( "fchownat(path)", ARG2 ); +} + +// SYS_fexecve 492 +// int fexecve(int fd, char *const argv[], char *const envp[]); +PRE(sys_fexecve) +{ + PRINT("sys_fexecve ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + SARG1,ARG2,ARG3); + PRE_REG_READ3(long, "fexecve", + int, fd, char * const *, argv, + char * const *, envp); + PRE_MEM_RASCIIZ( "fexecve(argv)", ARG2 ); + PRE_MEM_RASCIIZ( "fexecve(envp)", ARG3 ); +} + +// SYS_freebsd11_fstatat 493 +// int fstatat(int fd, const char *path, struct stat *sb, int flag); +#if (FREEBSD_VERS >= FREEBSD_12) +PRE(sys_freebsd11_fstatat) +{ + PRINT("sys_freebsd11_fstatat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ4(int, "fstatat", + int, fd, const char *, path, struct freebsd11_stat *, buf, int, flag); + PRE_MEM_RASCIIZ( "fstatat(path)", ARG2 ); + PRE_MEM_WRITE( "fstatat(sb)", ARG3, sizeof(struct vki_freebsd11_stat) ); +} + +POST(sys_freebsd11_fstatat) +{ + POST_MEM_WRITE( ARG3, sizeof(struct vki_freebsd11_stat) ); +} +#else +PRE(sys_fstatat) +{ + PRINT("sys_fstatat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ4(int, "fstatat", + int, fd, const char *, path, struct stat *, buf, int, flag); + PRE_MEM_RASCIIZ( "fstatat(path)", ARG2 ); + PRE_MEM_WRITE( "fstatat(sb)", ARG3, sizeof(struct vki_freebsd11_stat) ); +} + +POST(sys_fstatat) +{ + POST_MEM_WRITE( ARG3, sizeof(struct vki_freebsd11_stat) ); +} +#endif + +// SYS_futimesat 494 +// int futimesat(int fd, const char *path, const struct timeval times[2]); +PRE(sys_futimesat) +{ + PRINT("sys_futimesat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ3(int, "futimesat", + int, fd, const char *, path, struct timeval *, times); + if (ARG2 != 0) + PRE_MEM_RASCIIZ( "futimesat(path)", ARG2 ); + if (ARG3 != 0) + PRE_MEM_READ( "futimesat(times)", ARG3, 2 * sizeof(struct vki_timeval) ); +} + +// SYS_linkat 495 +// int linkat(int fd1, const char *name1, int fd2, const char *name2, int flag); +PRE(sys_linkat) +{ + *flags |= SfMayBlock; + PRINT("sys_linkat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )",ARG1,ARG2,(char*)ARG2,ARG3,ARG4,(char*)ARG4,ARG5); + PRE_REG_READ5(int, "linkat", + int, fd1, const char *, name1, + int, fd2, const char *, name2, + int, flag); + PRE_MEM_RASCIIZ( "linkat(name1)", ARG2); + PRE_MEM_RASCIIZ( "linkat(name2)", ARG4); +} + +// SYS_mkdirat 496 +// int mkdirat(int fd, const char *path, mode_t mode); +PRE(sys_mkdirat) +{ + *flags |= SfMayBlock; + PRINT("sys_mkdirat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ3(int, "mkdirat", + int, fd, const char *, path, int, mode); + PRE_MEM_RASCIIZ( "mkdirat(path)", ARG2 ); +} + +// SYS_mkfifoat 497 +// int mkfifoat(int fd, const char *path, mode_t mode); +PRE(sys_mkfifoat) +{ + PRINT("sys_mkfifoat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x )", + SARG1,ARG2,(HChar*)ARG2,ARG3 ); + PRE_REG_READ3(int, "mkfifoat", + int, fd, const char *, path, vki_mode_t, mode); + PRE_MEM_RASCIIZ( "mkfifoat(path)", ARG2 ); +} + +// SYS_freebsd11_mknodat 498 +// int mknodat(int fd, const char *path, mode_t mode, dev_t dev); +#if (FREEBSD_VERS >= FREEBSD_12) +PRE(sys_freebsd11_mknodat) +{ + PRINT("sys_freebsd11_mknodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4 ); + PRE_REG_READ4(long, "mknodat", + int, dfd, const char *, pathname, int, mode, unsigned, dev); + PRE_MEM_RASCIIZ( "mknodat(pathname)", ARG2 ); +} +#else +PRE(sys_mknodat) +{ + PRINT("sys_mknodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4 ); + PRE_REG_READ4(long, "mknodat", + int, dfd, const char *, pathname, int, mode, unsigned, dev); + PRE_MEM_RASCIIZ( "mknodat(pathname)", ARG2 ); +} +#endif + +// SYS_openat 499 +// int openat(int fd, const char *path, int flags, ...); +PRE(sys_openat) +{ + + if (ARG3 & VKI_O_CREAT) { + // 4-arg version + PRINT("sys_openat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,(char*)ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "openat", + int, fd, const char *, path, int, flags, vki_mode_t, mode); + } else { + // 3-arg version + PRINT("sys_openat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )",ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ3(int, "openat", + int, fd, const char *, path, int, flags); + } + + if (ARG1 != (unsigned)VKI_AT_FDCWD && !ML_(fd_allowed)(ARG1, "openat", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_RASCIIZ( "openat(path)", ARG2 ); + + /* Otherwise handle normally */ + *flags |= SfMayBlock; +} + +POST(sys_openat) +{ + vg_assert(SUCCESS); + if (!ML_(fd_allowed)(RES, "openat", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_with_given_name)(tid, RES, (HChar*)ARG2); + } +} + +// SYS_readlinkat 500 +// ssize_t readlinkat(int fd, const char *restrict path, char *restrict buf, +// size_t bufsize); +PRE(sys_readlinkat) +{ + HChar name[25]; + Word saved = SYSNO; + + PRINT("sys_readlinkat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %llu )", ARG1,ARG2,(char*)ARG2,ARG3,(ULong)ARG4); + PRE_REG_READ4(ssize_t, "readlinkat", + int, fd, const char *, path, char *, buf, int, bufsize); + PRE_MEM_RASCIIZ( "readlinkat(path)", ARG2 ); + PRE_MEM_WRITE( "readlinkat(buf)", ARG3,ARG4 ); + + /* + * Handle the case where readlinkat is looking at /proc/curproc/file or + * /proc//file. + */ + VG_(sprintf)(name, "/proc/%d/file", VG_(getpid)()); + if (ML_(safe_to_deref)((void*)ARG2, 1) + && (VG_(strcmp)((HChar *)ARG2, name) == 0 + || VG_(strcmp)((HChar *)ARG2, "/proc/curproc/file") == 0)) { + VG_(sprintf)(name, "/proc/self/fd/%d", VG_(cl_exec_fd)); + SET_STATUS_from_SysRes( VG_(do_syscall4)(saved, ARG1, (UWord)name, + ARG3, ARG4)); + } else { + /* Normal case */ + SET_STATUS_from_SysRes( VG_(do_syscall4)(saved, ARG1, ARG2, ARG3, ARG4)); + } +} + +POST(sys_readlinkat) +{ + POST_MEM_WRITE( ARG3, RES ); +} + +// SYS_renameat 501 +// int renameat(int fromfd, const char *from, int tofd, const char *to); +PRE(sys_renameat) +{ + PRINT("sys_renameat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s) )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4,(char*)ARG4); + PRE_REG_READ4(int, "renameat", + int, fromfd, const char *, from, + int, tofd, const char *, to); + PRE_MEM_RASCIIZ( "renameat(oldpath)", ARG2 ); + PRE_MEM_RASCIIZ( "renameat(newpath)", ARG4 ); +} + +// SYS_symlinkat 502 +// int symlinkat(const char *name1, int fd, const char *name2); +PRE(sys_symlinkat) +{ + *flags |= SfMayBlock; + PRINT("sys_symlinkat ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s) )",ARG1,(char*)ARG1,ARG2,ARG3,(char*)ARG3); + PRE_REG_READ3(int, "symlinkat", + const char *, name1, int, fd, const char *, name2); + PRE_MEM_RASCIIZ( "symlinkat(name1)", ARG1 ); + PRE_MEM_RASCIIZ( "symlinkat(name2)", ARG3 ); +} + +// SYS_unlinkat 503 +// int unlinkat(int fd, const char *path, int flag); +PRE(sys_unlinkat) +{ + *flags |= SfMayBlock; + PRINT("sys_unlinkat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s) )", ARG1,ARG2,(char*)ARG2); + PRE_REG_READ3(int, "unlinkat", int, fd, const char *, path, int, flag); + PRE_MEM_RASCIIZ( "unlinkat(path)", ARG2 ); +} + +// SYS_posix_openpt 504 +// int posix_openpt(int oflag); +PRE(sys_posix_openpt) +{ + PRINT("sys_posix_openpt ( %" FMT_REGWORD "d )", SARG2); + PRE_REG_READ1(int, "posix_openpt", int, oflag); + +} + +// SYS_gssd_syscall 505 +// @todo +// see https://www.freebsd.org/cgi/man.cgi?format=html&query=gssapi(3) +// syscalls.master says ; 505 is initialised by the kgssapi code, if present. + +// SYS_jail_get 506 +// int jail_get(struct iovec *iov, u_int niov, int flags); +PRE(sys_jail_get) +{ + PRINT("sys_jail_get ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3); + PRE_REG_READ3(int, "jail_get", struct vki_iovec *, iov, unsigned int, + niov, int, flags); + PRE_MEM_READ("jail_get(iov)", ARG1, ARG2 * sizeof(struct vki_iovec)); +} + +// SYS_jail_set 507 +// int jail_set(struct iovec *iov, u_int niov, int flags); +PRE(sys_jail_set) +{ + PRINT("sys_jail_set ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3); + PRE_REG_READ3(int, "jail_set", struct vki_iovec *, iov, unsigned int, + niov, int, flags); + PRE_MEM_READ("jail_set(iovs)", ARG1, ARG2 * sizeof(struct vki_iovec)); +} + +// SYS_jail_remove 508 +// int jail_remove(int jid); +PRE(sys_jail_remove) +{ + PRINT("sys_jail_remove ( %" FMT_REGWORD "d )", SARG1); + PRE_REG_READ1(int, "jail_remove", int, jid); +} + +// SYS_closefrom 509 +// void closefrom(int lowfd); +PRE(sys_closefrom) +{ + PRINT("sys_closefrom ( %" FMT_REGWORD "dx )", SARG1); + PRE_REG_READ1(int, "closefrom", int, lowfd); + + /* + * Can't pass this on to the kernel otherwise it will close + * all of the host files like the log + */ + + for (int i = ARG1; i < VG_(fd_soft_limit); ++i) { + VG_(close)(i); + } + + SET_STATUS_Success(0); +} + +// SYS___semctl 510 +// int semctl(int semid, int semnum, int cmd, ...); +// int __semctl(int semid, int semnum, int cmd, _Inout_ union semun *arg); +PRE(sys___semctl) +{ + switch (ARG3) { + case VKI_IPC_INFO: + case VKI_SEM_INFO: + PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "semctl", + int, semid, int, semnum, int, cmd, struct seminfo *, arg); + break; + case VKI_IPC_STAT: + case VKI_SEM_STAT: + case VKI_IPC_SET: + PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "semctl", + int, semid, int, semnum, int, cmd, struct semid_ds *, arg); + break; + case VKI_GETALL: + case VKI_SETALL: + PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "semctl", + int, semid, int, semnum, int, cmd, unsigned short *, arg); + break; + default: + PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "semctl", + int, semid, int, semnum, int, cmd); + break; + } + ML_(generic_PRE_sys_semctl)(tid, ARG1,ARG2,ARG3,ARG4); +} + +POST(sys___semctl) +{ + ML_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3,ARG4); +} + +// SYS_msgctl 511 +// int msgctl(int msqid, int cmd, struct msqid_ds *buf); +PRE(sys_msgctl) +{ + PRINT("sys_msgctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1,SARG2,ARG3 ); + + PRE_REG_READ3(int, "msgctl", int, msqid, int, cmd, struct msqid_ds *, buf); + + switch (ARG2 /* cmd */) { + case VKI_IPC_STAT: + PRE_MEM_WRITE( "msgctl(IPC_STAT, buf)", + ARG3, sizeof(struct vki_msqid_ds) ); + break; + case VKI_IPC_SET: + PRE_MEM_READ( "msgctl(IPC_SET, buf)", + ARG3, sizeof(struct vki_msqid_ds) ); + break; + } +} + +POST(sys_msgctl) +{ + switch (ARG2 /* cmd */) { + case VKI_IPC_STAT: + POST_MEM_WRITE( ARG3, sizeof(struct vki_msqid_ds) ); + break; + } +} + + +// SYS_shmctl 512 +// int shmctl(int shmid, int cmd, struct shmid_ds *buf); +PRE(sys_shmctl) +{ + PRINT("sys_shmctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,SARG2,ARG3); + PRE_REG_READ3(int, "shmctl", + int, shmid, int, cmd, struct vki_shmid_ds *, buf); + switch (ARG2 /* cmd */) { + case VKI_IPC_STAT: + PRE_MEM_WRITE( "shmctl(IPC_STAT, buf)", + ARG3, sizeof(struct vki_shmid_ds) ); + break; + case VKI_IPC_SET: + PRE_MEM_READ( "shmctl(IPC_SET, buf)", + ARG3, sizeof(struct vki_shmid_ds) ); + break; + } +} + +POST(sys_shmctl) +{ + if (ARG2 == VKI_IPC_STAT) { + POST_MEM_WRITE( ARG3, sizeof(struct vki_shmid_ds) ); + } +} + +// SYS_lpathconf 513 +// long lpathconf(const char *path, int name); +PRE(sys_lpathconf) +{ + PRINT("sys_lpathconf ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d)", ARG1, SARG2); + PRE_REG_READ2(long, "lpathconf", const char *, path, int, name); + PRE_MEM_RASCIIZ("lpathconf(path)", ARG1); +} + +// SYS___cap_rights_get 515 +// note extra 1st argument for the internal function which is not present +// in the public interface +// int __cap_rights_get(int version, int fd, cap_rights_t *rights); +PRE(sys_cap_rights_get) +{ + PRINT("sys_cap_rights_get ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, SARG2, ARG3); + PRE_REG_READ3(long, "cap_rights_get", int, version, int, fd, vki_cap_rights_t*, rights); + PRE_MEM_WRITE("cap_rights_get(rights)", ARG3, sizeof(vki_cap_rights_t)); +} + +POST(sys_cap_rights_get) +{ + POST_MEM_WRITE(ARG2, sizeof(vki_cap_rights_t)); +} + +// SYS_cap_enter 516 +// int cap_enter(void); +PRE(sys_cap_enter) +{ + PRINT("%s", "sys_cap_enter ( )"); + PRE_REG_READ0(int, "cap_enter"); + static Bool warning_given = False; + if (!warning_given) { + warning_given = True; + capabiltyMode = True; + VG_(umsg)( + "WARNING: Valgrind may not operate correctly in capability mode.\n" + " Please consider disabling capability by using the RUNNING_ON_VALGRIND mechanism.\n" + " See http://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq\n"); + } +} + +// SYS_cap_getmode 517 +// int cap_getmode(u_int *modep); +PRE(sys_cap_getmode) +{ + PRINT("sys_cap_getmode ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "cap_getmode", u_int*, modep); + PRE_MEM_WRITE("cap_getmode(modep)", ARG1, sizeof(u_int)); +} + +POST(sys_cap_getmode) +{ + POST_MEM_WRITE(ARG1, sizeof(u_int)); +} + +static vki_sigset_t pdfork_saved_mask; + +// SYS_pdfork 518 +// pid_t pdfork(int *fdp, int flags); +PRE(sys_pdfork) +{ + Bool is_child; + Int child_pid; + vki_sigset_t mask; + + PRINT("sys_pdfork ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2); + PRE_REG_READ2(pid_t, "pdfork", int*, fdp, int, flags); + + /* Block all signals during fork, so that we can fix things up in + the child without being interrupted. */ + VG_(sigfillset)(&mask); + VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, &pdfork_saved_mask); + + VG_(do_atfork_pre)(tid); + + SET_STATUS_from_SysRes( VG_(do_syscall2)(__NR_pdfork, ARG1, ARG2) ); + + if (!SUCCESS) return; + + // RES is 0 for child, non-0 (the child's PID) for parent. + is_child = ( RES == 0 ? True : False ); + child_pid = ( is_child ? -1 : RES ); + + if (is_child) { + VG_(do_atfork_child)(tid); + + /* restore signal mask */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &pdfork_saved_mask, NULL); + } else { + VG_(do_atfork_parent)(tid); + + PRINT(" fork: process %d created child %d\n", VG_(getpid)(), child_pid); + + /* restore signal mask */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &pdfork_saved_mask, NULL); + } + + if (ARG1) { + PRE_MEM_WRITE( "pdfork(fdp)", ARG1, sizeof(int) ); + } +} + +POST(sys_pdfork) +{ + if (ARG1) { + POST_MEM_WRITE( ARG1, sizeof(int) ); + } +} + +// pdkill 519 +//int pdkill(int fd, int signum) +PRE(sys_pdkill) +{ + PRINT("sys_pdkill ( %" FMT_REGWORD "u, %" FMT_REGWORD "d )", ARG1, SARG2); + PRE_REG_READ2(int, "pdkill", int, fd, int, signum); + + if (!ML_(client_signal_OK)(ARG2)) { + SET_STATUS_Failure( VKI_EINVAL ); + return; + } + + /* If we're sending SIGKILL, check to see if the target is one of + our threads and handle it specially. */ + if (ARG2 == VKI_SIGKILL && ML_(do_sigkill)(ARG1, -1)) + SET_STATUS_Success(0); + + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "pdkill: sent signal %ld to fd %ld\n", + SARG2, SARG1); + + /* This kill might have given us a pending signal. Ask for a check once + the syscall is done. */ + *flags |= SfPollAfter; + +} + +// SYS_pdgetpid 520 +// int pdgetpid(int fd, pid_t *pidp); +PRE(sys_pdgetpid) +{ + PRINT("pdgetpid ( %" FMT_REGWORD "d, %#lx )", SARG1, ARG2); + PRE_REG_READ2(int, "pdgetpid", + int, fd, pid_t*, pidp); + PRE_MEM_WRITE( "pdgetpid(pidp))", ARG2, sizeof(vki_pid_t) ); +} + +POST(sys_pdgetpid) +{ + POST_MEM_WRITE( ARG2, sizeof(vki_pid_t) ); +} + +// SYS_pselect 522 + +// int pselect(int nfds, fd_set * restrict readfds, fd_set * restrict writefds, +// fd_set * restrict exceptfds, +// const struct timespec * restrict timeout, +// const sigset_t * restrict newsigmask); +PRE(sys_pselect) +{ + *flags |= SfMayBlock | SfPostOnFail; + PRINT("sys_pselect ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" + FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + SARG1, ARG2, ARG3, ARG4, ARG5, ARG6); + PRE_REG_READ6(int, "pselect", + int, nfds, vki_fd_set *, readfds, vki_fd_set *, writefds, + vki_fd_set *, exceptfds, struct vki_timespec *, timeout, + const sigset_t *, newsigmask); + // XXX: this possibly understates how much memory is read. + if (ARG2 != 0) + PRE_MEM_READ( "pselect(readfds)", + ARG2, ARG1/8 /* __FD_SETSIZE/8 */ ); + if (ARG3 != 0) + PRE_MEM_READ( "pselect(writefds)", + ARG3, ARG1/8 /* __FD_SETSIZE/8 */ ); + if (ARG4 != 0) + PRE_MEM_READ( "pselect(exceptfds)", + ARG4, ARG1/8 /* __FD_SETSIZE/8 */ ); + if (ARG5 != 0) + PRE_MEM_READ( "pselect(timeout)", ARG5, sizeof(struct vki_timeval) ); + + if (ARG6 != 0) { + PRE_MEM_READ( "pselect(sig)", ARG6, sizeof(vki_sigset_t) ); + ARG6 = ML_(make_safe_mask)("syswrap.pselect.1", (Addr)ARG6); + } +} + +POST(sys_pselect) +{ + ML_(free_safe_mask) ( (Addr)ARG6 ); +} + +// SYS_getloginclass 523 +// int getloginclass(char *name, size_t len); +PRE(sys_getloginclass) +{ + PRINT("sys_getloginclass ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2); + PRE_REG_READ2(int, "getloginclass", char *, name, size_t, len); + // The buffer should be at least MAXLOGNAME bytes in length. + PRE_MEM_WRITE("getloginclass(name)", ARG1, ARG2); +} + +POST(sys_getloginclass) +{ + POST_MEM_WRITE(ARG1, ARG2); +} + +// SYS_setloginclass 524 +// int setloginclass(const char *name); +PRE(sys_setloginclass) +{ + PRINT("sys_setloginclass ( %#" FMT_REGWORD "x(%s) )", ARG1, (HChar*)ARG1); + PRE_REG_READ1(int, "setloginclass", const char *, name); + PRE_MEM_RASCIIZ("rctl_setloginclass(name)", ARG1); +} + +// SYS_rctl_get_racct 525 +// int rctl_get_racct(const char *inbufp, size_t inbuflen, char *outbufp, +// size_t outbuflen); +PRE(sys_rctl_get_racct) +{ + PRINT("sys_rctl_get_racct ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "xd, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4); + PRE_REG_READ4(int, "rctl_get_racct", const char *, inbufp, size_t, inbuflen, char *, outbufp, + size_t, outbuflen); + PRE_MEM_READ("rctl_get_racct(inbufp)", ARG1, ARG2); + PRE_MEM_WRITE("rctl_get_racct(outbufp)", ARG3, ARG4); +} + +POST(sys_rctl_get_racct) +{ + POST_MEM_WRITE(ARG3, ARG4); +} + +// SYS_rctl_get_rules 526 +// int rctl_get_rules(const char *inbufp, size_t inbuflen, char *outbufp, +// size_t outbuflen); +PRE(sys_rctl_get_rules) +{ + PRINT("sys_rctl_get_rules ( %#" FMT_REGWORD "xd, %" FMT_REGWORD "u, %#" FMT_REGWORD "xd, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4); + PRE_REG_READ4(int, "rctl_get_rules", const char *, inbufp, size_t, inbuflen, char *, outbufp, + size_t, outbuflen); + PRE_MEM_READ("rctl_get_rules(inbufp)", ARG1, ARG2); + PRE_MEM_WRITE("rctl_get_rules(outbufp)", ARG3, ARG4); +} + +POST(sys_rctl_get_rules) +{ + POST_MEM_WRITE(ARG3, ARG4); +} + +// SYS_rctl_get_limits 527 +// int rctl_get_limits(const char *inbufp, size_t inbuflen, char *outbufp, +// size_t outbuflen); +PRE(sys_rctl_get_limits) +{ + PRINT("sys_rctl_get_limits ( %#" FMT_REGWORD "xd, %" FMT_REGWORD "u, %#" FMT_REGWORD "xd, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4); + PRE_REG_READ4(int, "rctl_get_limits", const char *, inbufp, size_t, inbuflen, char *, outbufp, + size_t, outbuflen); + PRE_MEM_READ("rctl_get_limits(inbufp)", ARG1, ARG2); + PRE_MEM_WRITE("rctl_get_limits(outbufp)", ARG3, ARG4); +} + +POST(sys_rctl_get_limits) +{ + POST_MEM_WRITE(ARG3, ARG4); +} + +// SYS_rctl_add_rule 528 +// int rctl_add_rule(const char *inbufp, size_t inbuflen, char *outbufp, +// size_t outbuflen); +PRE(sys_rctl_add_rule) +{ + PRINT("sys_rctl_add_rule ( %#" FMT_REGWORD "xd, %" FMT_REGWORD "u, %#" FMT_REGWORD "xd, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4); + PRE_REG_READ2(int, "rctl_add_rule", const char *, inbufp, size_t, inbuflen); + PRE_MEM_READ("rctl_add_rule(inbufp)", ARG1, ARG2); + // man page says + // The outbufp and outbuflen arguments are unused + //PRE_MEM_WRITE("rctl_add_rule(outbufp)", ARG3, ARG4); +} + +POST(sys_rctl_add_rule) +{ + //POST_MEM_WRITE(ARG3, ARG4); +} + +// SYS_rctl_remove_rule 529 +// int rctl_remove_rule(const char *inbufp, size_t inbuflen, char *outbufp, +// size_t outbuflen); +PRE(sys_rctl_remove_rule) +{ + PRINT("sys_rctl_remove_rule ( %#" FMT_REGWORD "xd, %" FMT_REGWORD "u, %#" FMT_REGWORD "xd, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4); + PRE_REG_READ2(int, "rctl_remove_rule", const char *, inbufp, size_t, inbuflen); + PRE_MEM_READ("rctl_remove_rule(inbufp)", ARG1, ARG2); + // man page says + // The outbufp and outbuflen arguments are unused + //PRE_MEM_WRITE("rctl_remove_rule(outbufp)", ARG3, ARG4); +} + +POST(sys_rctl_remove_rule) +{ + //POST_MEM_WRITE(ARG3, ARG4); +} + +// SYS_posix_fallocate 530 +// x86/amd64 + +// SYS_posix_fadvise 531 +// x86/amd64 + +// SYS_wait6 532 +// amd64 / x86 + +// SYS_cap_rights_limit 533 +//int cap_rights_limit(int fd, const cap_rights_t *rights); +PRE(sys_cap_rights_limit) +{ + PRINT("sys_cap_rights_limit ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2); + PRE_REG_READ2(int, "cap_rights_limit", + int, fd, const cap_rights_t *, rights); + PRE_MEM_READ( "cap_rights_limit(rights)", ARG2, sizeof(struct vki_cap_rights) ); +} + +// SYS_cap_ioctls_limit 534 +// int cap_ioctls_limit(int fd, const unsigned long *cmds, size_t ncmds); +PRE(sys_cap_ioctls_limit) +{ + PRINT("cap_ioctls_limit ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3); + PRE_REG_READ3(int, "cap_ioctls_limit", + int, fd, unsigned long*, rights, vki_size_t, ncmds); + // "can be up to 256" taking that to not be inclusive + if (ARG3 < 256 ) { + PRE_MEM_READ( "cap_ioctls_limit(cmds))", ARG2, ARG3*sizeof(unsigned long) ); + } + // else fail? +} + +// SYS_cap_ioctls_get 535 +// int cap_ioctls_get(int fd, unsigned long *cmds, size_t maxcmds); +PRE(sys_cap_ioctls_get) +{ + PRINT("sys_cap_ioctls_get ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", SARG1, ARG2, ARG3); + PRE_REG_READ3(int, "cap_ioctls_get", int, fd, unsigned long *, cmds, size_t, maxcmds); + if (ARG3 < 256) { + PRE_MEM_WRITE("cap_ioctls_get(cmds)", ARG2, ARG3*sizeof(unsigned long)); + } +} + +POST(sys_cap_ioctls_get) +{ + if (ARG3 < 256) { + POST_MEM_WRITE(ARG2, ARG3*sizeof(unsigned long)); + } +} + + +// SYS_cap_fcntls_limit 536 +//int cap_fcntls_limit(int fd, uint32_t fcntlrights); +PRE(sys_cap_fcntls_limit) +{ + PRINT("cap_fcntls_limit ( %" FMT_REGWORD "d, %" FMT_REGWORD "u )", SARG1, ARG2); + PRE_REG_READ2(long, "cap_fcntls_limit", + int, fd, vki_uint32_t, fcntlrights); +} + +// SYS_cap_fcntls_get 537 +// int cap_fcntls_get(int fd, uint32_t *fcntlrightsp); +PRE(sys_cap_fcntls_get) +{ + PRINT("sys_cap_fcntls_get ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2); + PRE_REG_READ2(int, "cap_fcntls_get", int, fd, uint32_t *, fcntlrightsp); + PRE_MEM_WRITE("cap_fcntls_get(fcntlrightsp)", ARG2, sizeof(uint32_t)); +} + +POST(sys_cap_fcntls_get) +{ + POST_MEM_WRITE(ARG2, sizeof(uint32_t)); +} + +// SYS_bindat 538 +// int bindat(int fd, int s, const struct sockaddr *addr, socklen_t addrlen); +PRE(sys_bindat) +{ + PRINT("sys_bindat ( %" FMT_REGWORD "d, %" FMT_REGWORD "dx, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", + SARG1, SARG2, ARG3, ARG4); + PRE_REG_READ4(int, "bindat", int, fd, int, s, const struct vki_sockaddr *, name, vki_socklen_t, namelen); + PRE_MEM_READ("bindat(name)", ARG3, ARG4); +} + +// SYS_connectat 539 +// int connectat(int fd, int s, const struct sockaddr *name, socklen_t namelen); +PRE(sys_connectat) +{ + PRINT("sys_connectat ( %" FMT_REGWORD "d, %" FMT_REGWORD "dx, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", + SARG1, SARG2, ARG3, ARG4); + PRE_REG_READ4(int, "connectat", int, fd, int, s, const struct vki_sockaddr *, name, vki_socklen_t, namelen); + PRE_MEM_READ("connectat(name)", ARG3, ARG4); +} + +// SYS_chflagsat 540 +// int chflagsat(int fd, const char *path, unsigned long flags, int atflag); +PRE(sys_chflagsat) +{ + PRINT("sys_chglagsat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "d )", + SARG1, ARG2, ARG3, SARG4); + PRE_REG_READ4(int, "chflagsat", int, fd, const char *, path, unsigned long, flags, int, atflag); + PRE_MEM_RASCIIZ("chflagsat(path)", ARG2); +} + +// SYS_accept4 541 +// int accept4(int s, struct sockaddr * restrict addr, +// socklen_t * restrict addrlen, int flags); +PRE(sys_accept4) +{ + *flags |= SfMayBlock; + PRINT("sys_accept4 ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u)",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "accept4", + int, s, struct sockaddr *, addr, int, *addrlen, int, flags); + ML_(generic_PRE_sys_accept)(tid, ARG1,ARG2,ARG3); +} + +POST(sys_accept4) +{ + SysRes r; + vg_assert(SUCCESS); + r = ML_(generic_POST_sys_accept)(tid, VG_(mk_SysRes_Success)(RES), + ARG1,ARG2,ARG3); + SET_STATUS_from_SysRes(r); +} + +// SYS_pipe2 542 +// int pipe2(int fildes[2], int flags); +PRE(sys_pipe2) +{ + PRINT("sys_pipe2 ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2); + PRE_REG_READ2(int, "pipe2", + int *, fildes, int, flags); + PRE_MEM_WRITE("pipe2(fildes)", ARG1, 2 * sizeof(int)); + +} + +POST(sys_pipe2) +{ + int *fildes; + + if (RES != 0) + return; + + POST_MEM_WRITE(ARG1, 2 * sizeof(int)); + fildes = (int *)ARG1; + + if (!ML_(fd_allowed)(fildes[0], "pipe2", tid, True) || + !ML_(fd_allowed)(fildes[1], "pipe2", tid, True)) { + VG_(close)(fildes[0]); + VG_(close)(fildes[1]); + SET_STATUS_Failure( VKI_EMFILE ); + } else if (VG_(clo_track_fds)) { + ML_(record_fd_open_nameless)(tid, fildes[0]); + ML_(record_fd_open_nameless)(tid, fildes[1]); + } +} + +// SYS_aio_mlock 543 +// int aio_mlock(struct aiocb *iocb); +PRE(sys_aio_mlock) +{ + PRINT("sys_aio_mlock ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "aio_mlock", struct vki_aiocb *, iocb); + PRE_MEM_READ("aio_mlock(iocb", ARG1, sizeof(struct vki_aiocb)); + // this locks memory into RAM, don't think that we need to do + // anything extra +} + +// SYS_procctl 544 +// amd64 / x86 + +// SYS_ppoll 545 +// int ppoll(struct pollfd fds[], nfds_t nfds, +// const struct timespec * restrict timeout, +// const sigset_t * restrict newsigmask); +PRE(sys_ppoll) +{ + PRINT("sys_ppoll ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD + "x, %#" FMT_REGWORD "x )", + ARG1, ARG2, ARG3, ARG4); + UInt i; + struct vki_pollfd* fds = (struct vki_pollfd *)(Addr)ARG1; + *flags |= SfMayBlock | SfPostOnFail; + PRE_REG_READ4(long, "ppoll", + struct vki_pollfd *, fds, unsigned int, nfds, + struct vki_timespec *, timeout, vki_sigset_t *, newsigmask); + + if (ML_(safe_to_deref)(fds, ARG2*sizeof(struct vki_pollfd))) { + for (i = 0; i < ARG2; i++) { + PRE_MEM_READ( "ppoll(fds.fd)", + (Addr)(&fds[i].fd), sizeof(fds[i].fd) ); + PRE_MEM_READ( "ppoll(fds.events)", + (Addr)(&fds[i].events), sizeof(fds[i].events) ); + PRE_MEM_WRITE( "ppoll(fds.revents)", + (Addr)(&fds[i].revents), sizeof(fds[i].revents) ); + } + } + + if (ARG3) { + PRE_MEM_READ( "ppoll(timeout)", ARG3, + sizeof(struct vki_timespec) ); + } + if (ARG4) { + PRE_MEM_READ( "ppoll(newsigmask)", ARG4, sizeof(vki_sigset_t)); + ARG4 = ML_(make_safe_mask)("syswrap.ppoll.1", (Addr)ARG4); + } +} + +POST(sys_ppoll) +{ + if (SUCCESS && ((Word)RES != -1)) { + UInt i; + struct vki_pollfd* ufds = (struct vki_pollfd *)(Addr)ARG1; + for (i = 0; i < ARG2; i++) + POST_MEM_WRITE( (Addr)(&ufds[i].revents), sizeof(ufds[i].revents) ); + } + ML_(free_safe_mask) ( (Addr)ARG4 ); +} + +// SYS_futimens 546 +// int futimens(int fd, const struct timespec times[2]); +PRE(sys_futimens) +{ + PRINT("sys_futimens ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2); + PRE_REG_READ2(int, "futimens", int, fd, const struct timespec *, times); + PRE_MEM_READ("futimens(times)", ARG2, 2*sizeof(struct vki_timespec)); +} + +// SYS_utimensat 547 +// int utimensat(int fd, const char *path, const struct timespec times[2], +// int flag); +PRE(sys_utimensat) +{ + PRINT("sys_utimensat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )", + SARG1, ARG2, ARG3, SARG4); + PRE_REG_READ4(int, "utimensat", int, fd, const char *,path, const struct timespec *, times, + int, flag); + PRE_MEM_RASCIIZ("utimensat(path)", ARG2); + PRE_MEM_READ("utimensat(times)", ARG3, 2*sizeof(struct vki_timespec)); +} + +// SYS_fdatasync 550 +// int fdatasync(int fd); +PRE(sys_fdatasync) +{ + PRINT("sys_fdatasync ( %" FMT_REGWORD "d )",SARG1); + PRE_REG_READ1(int, "fdatasync", int, fd); +} + +#if (FREEBSD_VERS >= FREEBSD_12) +// SYS_fstat 551 +// int fstat(int fd, struct stat *sb); +PRE(sys_fstat) +{ + PRINT("sys_fstat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,ARG2); + PRE_REG_READ2(int, "fstat", int, fd, struct stat *, sb); + PRE_MEM_WRITE( "fstat(sb)", ARG2, sizeof(struct vki_stat) ); +} + +POST(sys_fstat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) ); +} + +// SYS_fstatat 552 +// int fstatat(int fd, const char *path, struct stat *sb, int flag); +PRE(sys_fstatat) +{ + PRINT("sys_fstatat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %" FMT_REGWORD "d )", SARG1,ARG2,(char*)ARG2,ARG3,SARG4); + PRE_REG_READ4(int, "fstatat", + int, fd, const char *, path, struct stat *, sb, int, flag); + PRE_MEM_RASCIIZ( "fstatat(path)", ARG2 ); + PRE_MEM_WRITE( "fstatat(sb)", ARG3, sizeof(struct vki_stat) ); +} + +POST(sys_fstatat) +{ + POST_MEM_WRITE( ARG3, sizeof(struct vki_stat) ); +} +// SYS_fhstat 553 +// int fhstat(const fhandle_t *fhp, struct stat *sb); +PRE(sys_fhstat) +{ + PRINT("sys_fhstat ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2); + PRE_REG_READ2(long, "fhstat", const vki_fhandle_t *, fhp, struct stat *, sb); + PRE_MEM_READ( "fhstat(fhp)", ARG1, sizeof(struct vki_fhandle) ); + PRE_MEM_WRITE( "fhstat(sb)", ARG2, sizeof(struct vki_stat) ); +} + +POST(sys_fhstat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) ); +} + +// SYS_getdirentries 554 +// ssize_t getdirentries(int fd, char *buf, size_t nbytes, off_t *basep); +PRE(sys_getdirentries) +{ + *flags |= SfMayBlock; + PRINT("sys_getdirentries ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", SARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(ssize_t, "getdirentries", + int, fd, char *, buf, + size_t, nbytes, + off_t *, basep); + PRE_MEM_WRITE( "getdirentries(buf)", ARG2, ARG3 ); + if (ARG4) + PRE_MEM_WRITE("getdirentries(basep)", ARG4, sizeof (vki_off_t)); +} + +POST(sys_getdirentries) +{ + vg_assert(SUCCESS); + if (RES > 0) { + POST_MEM_WRITE( ARG2, RES ); + if ( ARG4 != 0 ) + POST_MEM_WRITE( ARG4, sizeof (vki_off_t)); + } +} + +// SYS_statfs 555 +// int statfs(const char *path, struct statfs *buf); +PRE(sys_statfs) +{ + PRINT("sys_statfs ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(int, "statfs", const char *, path, struct statfs *, buf); + PRE_MEM_RASCIIZ( "statfs(path)", ARG1 ); + PRE_MEM_WRITE( "statfs(buf)", ARG2, sizeof(struct vki_statfs) ); +} + +POST(sys_statfs) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs) ); +} + +// SYS_fstatfs 556 +// int fstatfs(int fd, struct statfs *buf); +PRE(sys_fstatfs) +{ + PRINT("sys_fstatfs ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,ARG2); + PRE_REG_READ2(int, "fstatfs", + int, fd, struct vki_statfs *, buf); + PRE_MEM_WRITE( "fstatfs(buf)", ARG2, sizeof(struct vki_statfs) ); +} + +POST(sys_fstatfs) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs) ); +} + +// SYS_getfsstat 557 +// int getfsstat(struct statfs *buf, long bufsize, int mode); +PRE(sys_getfsstat) +{ + PRINT("sys_getfsstat ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "getfsstat", struct vki_statfs *, buf, long, len, int, flags); + PRE_MEM_WRITE( "getfsstat(buf)", ARG1, ARG2 ); +} + +POST(sys_getfsstat) +{ + vg_assert(SUCCESS); + if ((Word)RES != -1) { + POST_MEM_WRITE( ARG1, RES * sizeof(struct vki_statfs) ); + } +} + +// SYS_fhstatfs 558 +// int fhstatfs(const fhandle_t *fhp, struct statfs *buf); +PRE(sys_fhstatfs) +{ + PRINT("sys_fhstatfs ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2); + PRE_REG_READ2(long, "fhstatfs", + struct fhandle *, fhp, struct statfs *, buf); + PRE_MEM_READ( "fhstatfs(fhp)", ARG1, sizeof(struct vki_fhandle) ); + PRE_MEM_WRITE( "fhstatfs(buf)", ARG2, sizeof(struct vki_statfs) ); +} + +POST(sys_fhstatfs) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs) ); +} + +// SYS_mknodat 559 +// int mknodat(int fd, const char *path, mode_t mode, dev_t dev); +PRE(sys_mknodat) +{ + PRINT("sys_mknodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4 ); + PRE_REG_READ4(long, "mknodat", + int, fd, const char *, path, vki_mode_t, mode, vki_dev_t, dev); + PRE_MEM_RASCIIZ( "mknodat(pathname)", ARG2 ); +} + +// SYS_kevent 560 +// int kevent(int kq, const struct kevent *changelist, int nchanges, +// struct kevent *eventlist, int nevents, +// const struct timespec *timeout); +PRE(sys_kevent) +{ + PRINT("sys_kevent ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )\n", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6); + PRE_REG_READ6(int, "kevent", + int, kq, struct vki_kevent *, changelist, int, nchanges, + struct vki_kevent *, eventlist, int, nevents, + struct timespec *, timeout); + if (ARG2 != 0 && ARG3 != 0) + PRE_MEM_READ( "kevent(changelist)", ARG2, sizeof(struct vki_kevent)*ARG3 ); + if (ARG4 != 0 && ARG5 != 0) + PRE_MEM_WRITE( "kevent(eventlist)", ARG4, sizeof(struct vki_kevent)*ARG5); + if (ARG5 != 0) + *flags |= SfMayBlock; + if (ARG6 != 0) + PRE_MEM_READ( "kevent(timeout)", + ARG6, sizeof(struct vki_timespec)); +} + +POST(sys_kevent) +{ + vg_assert(SUCCESS); + if ((Word)RES != -1) { + if (ARG4 != 0) + POST_MEM_WRITE( ARG4, sizeof(struct vki_kevent)*RES) ; + } +} + +// SYS_cpuset_getdomain 561 +// x86 / amd64 + +// SYS_cpuset_setdomain 562 +// x86 / amd64 + +// SYS_getrandom 563 +// ssize_t getrandom(void *buf, size_t buflen, unsigned int flags); +PRE(sys_getrandom) +{ + PRINT("sys_getrandom ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3); + PRE_REG_READ3(ssize_t, "getrandom", + void *, buf, vki_size_t, buflen, unsigned int, flags); + PRE_MEM_WRITE( "getrandom(buf)", ARG1, ARG2 ); + if ((ARG3 & VKI_GRND_NONBLOCK) == 0) { + *flags |= SfMayBlock; + } +} + +POST(sys_getrandom) +{ + POST_MEM_WRITE( ARG1, ARG2 ); +} + +// SYS_getfhat 564 +// int getfhat(int fd, const char *path, fhandle_t *fhp, int flag); +PRE(sys_getfhat) +{ + PRINT("sys_getfhat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "x, %" FMT_REGWORD "d ", SARG1, ARG2, ARG3, SARG4); + PRE_REG_READ4(int, "getfhat", int, fd, const char*, path, vki_fhandle_t*, fhp, int, flag); + PRE_MEM_RASCIIZ( "getfhat(path)", ARG2 ); + PRE_MEM_WRITE("getfhat(fhp)", ARG3, sizeof(vki_fhandle_t)); +} + +POST(sys_getfhat) +{ + POST_MEM_WRITE(ARG3, sizeof(vki_fhandle_t)); +} + +// SYS_fhlink 565 +// int fhlink(fhandle_t *fhp, const char *to); +PRE(sys_fhlink) +{ + PRINT("sys_fhlink ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2); + PRE_REG_READ2(int, "fhlink", vki_fhandle_t *, fhp, const char *, to); + PRE_MEM_READ( "fhlink(fhp)", ARG1, sizeof(vki_fhandle_t)); + PRE_MEM_RASCIIZ("fhlink(buf)", ARG2); +} + +// SYS_fhlinkat 566 +// int fhlinkat(fhandle_t *fhp, int tofd, const char *to); +PRE(sys_fhlinkat) +{ + PRINT("sys_fhlinkat ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "xu ", ARG1, SARG2, ARG3); + PRE_REG_READ3(int, "fhlinkat", vki_fhandle_t *, fhp, int, tofd, const char *, to); + PRE_MEM_READ( "fhlinkat(fhp)", ARG1, sizeof(vki_fhandle_t)); + PRE_MEM_RASCIIZ("fhreadlink(to)", ARG3); +} + +// SYS_fhreadlink 567 +// int fhreadlink(fhandle_t *fhp, char *buf, size_t bufsize); +PRE(sys_fhreadlink) +{ + PRINT("sys_fhreadlink ( %#" FMT_REGWORD "x, %" FMT_REGWORD "x, %" FMT_REGWORD "u ", ARG1, ARG2, ARG3); + PRE_REG_READ3(int, "fhreadlink", vki_fhandle_t *, fhp, char *, buf, size_t, bufsize); + PRE_MEM_READ( "fhreadlink(fhp)", ARG1, sizeof(vki_fhandle_t)); + PRE_MEM_WRITE("fhreadlink(buf)", ARG2, ARG3); +} + +POST(sys_fhreadlink) +{ + POST_MEM_WRITE(ARG2, ARG3); +} + +#endif + +#if (FREEBSD_VERS >= FREEBSD_12_2) + +// SYS___sysctlbyname +// int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, +// const void *newp, size_t newlen); +// syscalls.master: +// int __sysctlbyname(_In_reads_(namelen) const char *name, size_t namelen, +// _Out_writes_bytes_opt_(*oldlenp) void *old, +// _Inout_opt_ size_t *oldlenp, _In_reads_bytes_opt_(newlen) void *new, +// size_t newlen ); +PRE(sys___sysctlbyname) +{ + // this is very much like SYS___sysctl, instead of having an OID with length + // here threre is an ascii string with length + // @todo PJF factor out the common functionality of the two + PRINT("sys___sysctlbyname ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,(const char*)ARG1,ARG2,ARG3,ARG4,ARG5 ); + PRE_REG_READ6(int, "__sysctlbyname", const char *, name, vki_size_t, namelen, + void *, oldp, vki_size_t *, oldlenp, + void *, newp, vki_size_t, newlen); + // read number of ints specified in ARG2 from mem pointed to by ARG1 + PRE_MEM_READ("__sysctlbyname(name)", (Addr)ARG1, ARG2 * sizeof(int)); + + // if 'newp' is not NULL can read namelen bytes from that addess + if (ARG5 != (UWord)NULL) + PRE_MEM_READ("__sysctlbyname(newp)", (Addr)ARG5, ARG6); + + // there are two scenarios for oldlenp/oldp + // 1. oldval is NULL and oldlenp is non-NULL + // this is a query of oldlenp so oldlenp will be written + // 2. Both are non-NULL + // this is a query of oldp, oldlenp will be read and oldp will + // be written + + // is oldlenp is not NULL, can write + if (ARG4 != (UWord)NULL) { + if (ARG3 != (UWord)NULL) { + // case 2 above + PRE_MEM_READ("__sysctlbyname(oldlenp)", (Addr)ARG4, sizeof(vki_size_t)); + if (ML_(safe_to_deref)((void*)(Addr)ARG4, sizeof(vki_size_t))) { + PRE_MEM_WRITE("__sysctlbyname(oldp)", (Addr)ARG3, *(vki_size_t *)ARG4); + } else { + VG_(dmsg)("Warning: Bad oldlenp address %p in sysctl\n", + (void *)(Addr)ARG4); + SET_STATUS_Failure ( VKI_EFAULT ); + } + } else { + // case 1 above + PRE_MEM_WRITE("__sysctlbyname(oldlenp)", (Addr)ARG4, sizeof(vki_size_t)); + } + } +} + +POST(sys___sysctlbyname) +{ + if (ARG4 != (UWord)NULL) { + if (ARG3 != (UWord)NULL) { + //POST_MEM_WRITE((Addr)ARG4, sizeof(vki_size_t)); + POST_MEM_WRITE((Addr)ARG3, *(vki_size_t *)ARG4); + } else + POST_MEM_WRITE((Addr)ARG4, sizeof(vki_size_t)); + } +} + +#endif + +#undef PRE +#undef POST + +const SyscallTableEntry ML_(syscall_table)[] = { + // syscall (handled specially) // 0 + BSDX_(__NR_exit, sys_exit), // 1 + BSDX_(__NR_fork, sys_fork), // 2 + GENXY(__NR_read, sys_read), // 3 + + GENX_(__NR_write, sys_write), // 4 + GENXY(__NR_open, sys_open), // 5 + GENXY(__NR_close, sys_close), // 6 + GENXY(__NR_wait4, sys_wait4), // 7 + + // 4.3 creat 8 + GENX_(__NR_link, sys_link), // 9 + GENX_(__NR_unlink, sys_unlink), // 10 + // obsol execv 11 + + GENX_(__NR_chdir, sys_chdir), // 12 + GENX_(__NR_fchdir, sys_fchdir), // 13 + GENX_(__NR_freebsd11_mknod, sys_mknod), // 14 + GENX_(__NR_chmod, sys_chmod), // 15 + + GENX_(__NR_chown, sys_chown), // 16 + GENX_(__NR_break, sys_brk), // 17 + // freebsd 4 getfsstat 18 + // 4.3 lseek 19 + + GENX_(__NR_getpid, sys_getpid), // 20 + BSDX_(__NR_mount, sys_mount), // 21 + BSDX_(__NR_unmount, sys_unmount), // 22 + GENX_(__NR_setuid, sys_setuid), // 23 + + GENX_(__NR_getuid, sys_getuid), // 24 + GENX_(__NR_geteuid, sys_geteuid), // 25 + BSDXY(__NR_ptrace, sys_ptrace), // 26 + BSDXY(__NR_recvmsg, sys_recvmsg), // 27 + + BSDX_(__NR_sendmsg, sys_sendmsg), // 28 + BSDXY(__NR_recvfrom, sys_recvfrom), // 29 + BSDXY(__NR_accept, sys_accept), // 30 + BSDXY(__NR_getpeername, sys_getpeername), // 31 + + BSDXY(__NR_getsockname, sys_getsockname), // 32 + GENX_(__NR_access, sys_access), // 33 + BSDX_(__NR_chflags, sys_chflags), // 34 + BSDX_(__NR_fchflags, sys_fchflags), // 35 + + GENX_(__NR_sync, sys_sync), // 36 + GENX_(__NR_kill, sys_kill), // 37 + // 4.3 stat 38 + GENX_(__NR_getppid, sys_getppid), // 39 + + // 4.3 lstat 40 + GENXY(__NR_dup, sys_dup), // 41 + + BSDXY(__NR_freebsd10_pipe, sys_pipe), // 42 + GENX_(__NR_getegid, sys_getegid), // 43 + + GENX_(__NR_profil, sys_ni_syscall), // 44 + GENX_(__NR_ktrace, sys_ni_syscall), // 45 + // 4.3 sigaction 46 + GENX_(__NR_getgid, sys_getgid), // 47 + + // 4.3 sigaction (int sigset) 48 + BSDXY(__NR_getlogin, sys_getlogin), // 49 + BSDX_(__NR_setlogin, sys_setlogin), // 50 + GENX_(__NR_acct, sys_acct), // 51 + + // 4.3 sigpending 52 + GENXY(__NR_sigaltstack, sys_sigaltstack), // 53 + BSDXY(__NR_ioctl, sys_ioctl), // 54 + BSDX_(__NR_reboot, sys_reboot), // 55 + + BSDX_(__NR_revoke, sys_revoke), // 56 + GENX_(__NR_symlink, sys_symlink), // 57 + GENX_(__NR_readlink, sys_readlink), // 58 + GENX_(__NR_execve, sys_execve), // 59 + + GENX_(__NR_umask, sys_umask), // 60 + GENX_(__NR_chroot, sys_chroot), // 61 + // 4.3 fstat 62 + // 4.3 getgerninfo 63 + + // 4.3 getpagesize 64 + GENX_(__NR_msync, sys_msync), // 65 + BSDX_(__NR_vfork, sys_vfork), // 66 + // obsol vread 67 + + // obsol vwrite 68 + BSDX_(__NR_sbrk, sys_sbrk), // 69 + // not implemented in OS sstk 70 + // 4.3 mmap 71 + + // freebsd11 vadvise 72 + GENXY(__NR_munmap, sys_munmap), // 73 + GENXY(__NR_mprotect, sys_mprotect), // 74 + GENX_(__NR_madvise, sys_madvise), // 75 + + // obsol vhangup 76 + // obsol vlimit 77 + GENXY(__NR_mincore, sys_mincore), // 78 + GENXY(__NR_getgroups, sys_getgroups), // 79 + + GENX_(__NR_setgroups, sys_setgroups), // 80 + GENX_(__NR_getpgrp, sys_getpgrp), // 81 + GENX_(__NR_setpgid, sys_setpgid), // 82 + GENXY(__NR_setitimer, sys_setitimer), // 83 + + // 4.3 wait 84 + BSDX_(__NR_swapon, sys_swapon), // 85 + GENXY(__NR_getitimer, sys_getitimer), // 86 + // 4.3 gethostname 87 + + // 4.3 sethostname 88 + BSDX_(__NR_getdtablesize, sys_getdtablesize), // 89 + GENXY(__NR_dup2, sys_dup2), // 90 + + BSDXY(__NR_fcntl, sys_fcntl), // 92 + GENX_(__NR_select, sys_select), // 93 + GENX_(__NR_fsync, sys_fsync), // 95 + + GENX_(__NR_setpriority, sys_setpriority), // 96 + BSDXY(__NR_socket, sys_socket), // 97 + BSDX_(__NR_connect, sys_connect), // 98 + // 4.3 accept 99 + + GENX_(__NR_getpriority, sys_getpriority), // 100 + // 4.3 send 101 + // 4.3 recv 102 + // 4.3 sigreturn 103 + + BSDX_(__NR_bind, sys_bind), // 104 + BSDX_(__NR_setsockopt, sys_setsockopt), // 105 + BSDX_(__NR_listen, sys_listen), // 106 + // obsol vtimes 107 + + // 4.3 sigvec 108 + // 4.3 sigblock 109 + // 4.3 sigsetmask 110 + // 4.3 sigsuspend 111 + + // 4.3 sigstack 112 + // 4.3 recvmsg 113 + // 4.3 sendmsg 114 + // 4.3 vtrace 115 + + GENXY(__NR_gettimeofday, sys_gettimeofday), // 116 + GENXY(__NR_getrusage, sys_getrusage), // 117 + BSDXY(__NR_getsockopt, sys_getsockopt), // 118 + + GENXY(__NR_readv, sys_readv), // 120 + GENX_(__NR_writev, sys_writev), // 121 + GENX_(__NR_settimeofday, sys_settimeofday), // 122 + GENX_(__NR_fchown, sys_fchown), // 123 + + GENX_(__NR_fchmod, sys_fchmod), // 124 + // 4.3 recvfrom 125 + GENX_(__NR_setreuid, sys_setreuid), // 126 + GENX_(__NR_setregid, sys_setregid), // 127 + + GENX_(__NR_rename, sys_rename), // 128 + // 4.3 truncate 129 + // 4.3 ftruncate 130 + GENX_(__NR_flock, sys_flock), // 131 + + BSDX_(__NR_mkfifo, sys_mkfifo), // 132 + BSDX_(__NR_sendto, sys_sendto), // 133 + BSDX_(__NR_shutdown, sys_shutdown), // 134 + BSDXY(__NR_socketpair, sys_socketpair), // 135 + + GENX_(__NR_mkdir, sys_mkdir), // 136 + GENX_(__NR_rmdir, sys_rmdir), // 137 + GENX_(__NR_utimes, sys_utimes), // 138 + // 4.2 sigreturn 139 + + BSDXY(__NR_adjtime, sys_adjtime), // 140 + // 4.3 getpeername 141 + // 4.3 gethostid 142 + // 4.3 sethostid 143 + + // 4.3 getrlimit` 144 + // 4.3 setrlimit 145 + // 4.3 killpg 146 + GENX_(__NR_setsid, sys_setsid), // 147 + + BSDX_(__NR_quotactl, sys_quotactl), // 148 + // 4.3 quota 149 + // 4.3 getsockname 150 + // bsd/os sem_lock 151 + + // bsd/os sem_wakeup 152 + // bsd/os asyncdaemon 153 + + // no idea what the following syscall does + // unimp SYS_nlm_syscall 154 + + // a somewhat complicated NFS API + // takes a flag and a void* that can point to one of + // three different types of struct depending on the flag + // unimp SYS_nfssvc 155 + + // 4.3 getdirentries 156 + // freebsd 4 statfs 157 + // freebsd 4 fstatfs 158 + + BSDXY(__NR_lgetfh, sys_lgetfh), // 160 + BSDXY(__NR_getfh, sys_getfh), // 161 +#if (FREEBSD_VERS <= FREEBSD_10) + BSDXY(__NR_freebsd4_getdomainname, sys_freebsd4_getdomainname), // 162 + BSDX_(__NR_freebsd4_setdomainname, sys_freebsd4_setdomainname), // 163 + BSDXY(__NR_freebsd4_uname, sys_freebsd4_uname), // 164 +#endif + BSDXY(__NR_sysarch, sys_sysarch), // 165 + BSDXY(__NR_rtprio, sys_rtprio), // 166 + + // the following 3 seem only to be defines in a header + // semsys 169 + // msgsys 170 + // shmsys 171 + +#if (FREEBSD_VERS <= FREEBSD_10) + BSDXY(__NR_freebsd6_pread, sys_freebsd6_pread), // 173 + BSDX_(__NR_freebsd6_pwrite, sys_freebsd6_pwrite), // 174 +#endif + BSDX_(__NR_setfib, sys_setfib), // 175 + + // @todo PJF this exists on Darwin and Solaris as well + // and it isn't implememented on either + // looking at the manpage there is a rather fearsome + // timex struct with a mixture of ro and rw fields + // BSDXY(__NR_ntp_adjtime, sys_ntp_adjtime), // 176 + + // bsd/os sfork 177 + // bsd/os getdescriptor 178 + // bsd/os setdescriptor 179 + + GENX_(__NR_setgid, sys_setgid), // 181 + BSDX_(__NR_setegid, sys_setegid), // 182 + BSDX_(__NR_seteuid, sys_seteuid), // 183 + + // obs lfs_bmapv 184 + // obs lfs_markv 185 + // obs lfs_segclean 186 + // obs lfs_segwait 187 + +#if (FREEBSD_VERS >= FREEBSD_12) + BSDXY(__NR_freebsd11_stat, sys_freebsd11_stat), // 188 + BSDXY(__NR_freebsd11_fstat, sys_freebsd11_fstat), // 189 + BSDXY(__NR_freebsd11_lstat, sys_freebsd11_lstat), // 190 +#else + BSDXY(__NR_stat, sys_stat), // 188 + BSDXY(__NR_fstat, sys_fstat), // 189 + BSDXY(__NR_lstat, sys_lstat), // 190 +#endif + BSDX_(__NR_pathconf, sys_pathconf), // 191 + BSDX_(__NR_fpathconf, sys_fpathconf), // 192 + GENXY(__NR_getrlimit, sys_getrlimit), // 194 + GENX_(__NR_setrlimit, sys_setrlimit), // 195 +#if (FREEBSD_VERS >= FREEBSD_12) + BSDXY(__NR_freebsd11_getdirentries, sys_freebsd11_getdirentries), // 196 +#else + BSDXY(__NR_getdirentries, sys_getdirentries), // 196 +#endif +#if (FREEBSD_VERS <= FREEBSD_10) + BSDX_(__NR_freebsd6_mmap, sys_freebsd6_mmap), // 197 +#endif + // __syscall (handled specially) // 198 +#if (FREEBSD_VERS <= FREEBSD_10) + BSDX_(__NR_freebsd6_lseek, sys_freebsd6_lseek), // 199 + BSDX_(__NR_freebsd6_truncate, sys_freebsd6_truncate), // 200 + BSDX_(__NR_freebsd6_ftruncate, sys_freebsd6_ftruncate), // 201 +#endif + BSDXY(__NR___sysctl, sys___sysctl), // 202 + GENX_(__NR_mlock, sys_mlock), // 203 + + GENX_(__NR_munlock, sys_munlock), // 204 + BSDX_(__NR_undelete, sys_undelete), // 205 + BSDX_(__NR_futimes, sys_futimes), // 206 + GENX_(__NR_getpgid, sys_getpgid), // 207 + + // netbsd newreboot 208 + GENXY(__NR_poll, sys_poll), // 209 + + BSDXY(__NR_freebsd7___semctl, sys_freebsd7___semctl), // 220 + BSDX_(__NR_semget, sys_semget), // 221 + BSDX_(__NR_semop, sys_semop), // 222 + // obs semconfig 223 + + BSDXY(__NR_freebsd7_msgctl, sys_freebsd7_msgctl), // 224 + BSDX_(__NR_msgget, sys_msgget), // 225 + BSDX_(__NR_msgsnd, sys_msgsnd), // 226 + BSDXY(__NR_msgrcv, sys_msgrcv), // 227 + + BSDXY(__NR_shmat, sys_shmat), // 228 + BSDXY(__NR_freebsd7_shmctl, sys_freebsd7_shmctl), // 229 + BSDXY(__NR_shmdt, sys_shmdt), // 230 + BSDX_(__NR_shmget, sys_shmget), // 231 + + BSDXY(__NR_clock_gettime, sys_clock_gettime), // 232 + BSDX_(__NR_clock_settime, sys_clock_settime), // 233 + BSDXY(__NR_clock_getres, sys_clock_getres), // 234 + BSDXY(__NR_ktimer_create, sys_timer_create), // 235 + BSDX_(__NR_ktimer_delete, sys_timer_delete), // 236 + BSDXY(__NR_ktimer_settime, sys_timer_settime), // 237 + BSDXY(__NR_ktimer_gettime, sys_timer_gettime), // 238 + BSDX_(__NR_ktimer_getoverrun, sys_timer_getoverrun), // 239 + + GENXY(__NR_nanosleep, sys_nanosleep), // 240 + // unimpl SYS_ffclock_getcounter 241 + // unimpl SYS_ffclock_setestimate 242 + // unimpl SYS_ffclock_getestimate 243 + + BSDXY(__NR_clock_nanosleep, sys_clock_nanosleep), // 244 + // unimpl SYS_clock_getcpuclockid2 247 + + // unimpl SYS_ntp_gettime 248 + BSDXY(__NR_minherit, sys_minherit), // 250 + BSDX_(__NR_rfork, sys_rfork), // 251 + + // openbsd_poll // 252 + BSDX_(__NR_issetugid, sys_issetugid), // 253 + GENX_(__NR_lchown, sys_lchown), // 254 + BSDXY(__NR_aio_read, sys_aio_read), // 255 + BSDXY(__NR_aio_write, sys_aio_write), // 256 + BSDX_(__NR_lio_listio, sys_lio_listio), // 257 + + GENXY(__NR_freebsd11_getdents, sys_getdents), // 272 + BSDX_(__NR_lchmod, sys_lchmod), // 274 + // netbsd_lchown // 275 + + BSDX_(__NR_lutimes, sys_lutimes), // 276 + // netbsd msync 277 + // unimpl SYS_freebsd11_nstat 278 + // unimpl SYS_freebsd11_nfstat 279 + + // unimpl SYS_freebsd11_nlstat 280 + + BSDXY(__NR_preadv, sys_preadv), // 289 + BSDX_(__NR_pwritev, sys_pwritev), // 290 + + // freebsd 4 fhstatfs 297 + BSDXY(__NR_fhopen, sys_fhopen), // 298 +#if (FREEBSD_VERS >= FREEBSD_12) + BSDXY(__NR_freebsd11_fhstat, sys_freebsd11_fhstat), // 299 +#else + BSDXY(__NR_fhstat, sys_fhstat), // 299 +#endif + + BSDX_(__NR_modnext, sys_modnext), // 300 + BSDXY(__NR_modstat, sys_modstat), // 301 + BSDX_(__NR_modfnext, sys_modfnext), // 302 + BSDX_(__NR_modfind, sys_modfind), // 303 + + BSDX_(__NR_kldload, sys_kldload), // 304 + BSDX_(__NR_kldunload, sys_kldunload), // 305 + BSDX_(__NR_kldfind, sys_kldfind), // 306 + BSDX_(__NR_kldnext, sys_kldnext), // 307 + + BSDXY(__NR_kldstat, sys_kldstat), // 308 + BSDX_(__NR_kldfirstmod, sys_kldfirstmod), // 309 + GENX_(__NR_getsid, sys_getsid), // 310 + BSDX_(__NR_setresuid, sys_setresuid), // 311 + + BSDX_(__NR_setresgid, sys_setresgid), // 312 + // obsol signanosleep 313 + BSDX_(__NR_aio_return, sys_aio_return), // 314 + BSDX_(__NR_aio_suspend, sys_aio_suspend), // 315 + + BSDX_(__NR_aio_cancel, sys_aio_cancel), // 316 + BSDX_(__NR_aio_error, sys_aio_error), // 317 + // freebsd 6 aio_read 318 + // freebsd 6 aio_write 319 + // freebsd 6 lio_listio 320 + BSDX_(__NR_yield, sys_yield), // 321 + // obs thr_sleep 322 + // obs thr_wakeup 323 + + GENX_(__NR_mlockall, sys_mlockall), // 324 + BSDX_(__NR_munlockall, sys_munlockall), // 325 + BSDXY(__NR___getcwd, sys___getcwd), // 326 + BSDX_(__NR_sched_setparam, sys_sched_setparam), // 327 + BSDXY(__NR_sched_getparam, sys_sched_getparam), // 328 + BSDX_(__NR_sched_setscheduler, sys_sched_setscheduler), // 329 + BSDX_(__NR_sched_getscheduler, sys_sched_getscheduler), // 330 + BSDX_(__NR_sched_yield, sys_sched_yield), // 331 + + BSDX_(__NR_sched_get_priority_max, sys_sched_get_priority_max), // 332 + BSDX_(__NR_sched_get_priority_min, sys_sched_get_priority_min), // 333 + BSDXY(__NR_sched_rr_get_interval, sys_sched_rr_get_interval), // 334 + BSDX_(__NR_utrace, sys_utrace), // 335 + + // freebsd 4 sendfile 336 + BSDXY(__NR_kldsym, sys_kldsym), // 337 + BSDX_(__NR_jail, sys_jail), // 338 + // unimpl SYS_nnpfs_syscall 339 + + BSDXY(__NR_sigprocmask, sys_sigprocmask), // 340 + BSDXY(__NR_sigsuspend, sys_sigsuspend), // 341 + // freebsd 4 sigaction 342 + BSDXY(__NR_sigpending, sys_sigpending), // 343 + + // freebsd 4 sigreturn 344 + BSDXY(__NR_sigtimedwait, sys_sigtimedwait), // 345 + BSDXY(__NR_sigwaitinfo, sys_sigwaitinfo), // 346 + BSDXY(__NR___acl_get_file, sys___acl_get_file), // 347 + + BSDX_(__NR___acl_set_file, sys___acl_set_file), // 348 + BSDXY(__NR___acl_get_fd, sys___acl_get_fd), // 349 + BSDX_(__NR___acl_set_fd, sys___acl_set_fd), // 350 + BSDX_(__NR___acl_delete_file, sys___acl_delete_file), // 351 + + BSDX_(__NR___acl_delete_fd, sys___acl_delete_fd), // 352 + BSDX_(__NR___acl_aclcheck_file, sys___acl_aclcheck_file), // 353 + BSDX_(__NR___acl_aclcheck_fd, sys___acl_aclcheck_fd), // 354 + BSDX_(__NR_extattrctl, sys_extattrctl), // 355 + BSDX_(__NR_extattr_set_file, sys_extattr_set_file), // 356 + BSDXY(__NR_extattr_get_file, sys_extattr_get_file), // 357 + BSDX_(__NR_extattr_delete_file, sys_extattr_delete_file), // 358 + BSDXY(__NR_aio_waitcomplete, sys_aio_waitcomplete), // 359 + + BSDXY(__NR_getresuid, sys_getresuid), // 360 + BSDXY(__NR_getresgid, sys_getresgid), // 361 + BSDXY(__NR_kqueue, sys_kqueue), // 362 +#if (FREEBSD_VERS >= FREEBSD_12) + BSDXY(__NR_freebsd11_kevent, sys_freebsd11_kevent), // 363 +#else + BSDXY(__NR_kevent, sys_kevent), // 363 +#endif + // obs __cap_get_proc 364 + // obs __cap_set_proc 365 + // obs __cap_get_fd 366 + // obs __cap_get_file 367 + // obs __cap_set_fd 368 + // obs __cap_set_file 369 + + BSDX_(__NR_extattr_set_fd, sys_extattr_set_fd), // 371 + BSDXY(__NR_extattr_get_fd, sys_extattr_get_fd), // 372 + BSDX_(__NR_extattr_delete_fd, sys_extattr_delete_fd), // 373 + BSDX_(__NR___setugid, sys___setugid), // 374 + // obs nfsclnt 375 + + BSDX_(__NR_eaccess, sys_eaccess), // 376 + // unimpl afs3_syscall 377 + BSDX_(__NR_nmount, sys_nmount), // 378 + // obs kse_exit 379 + // obs kse_wakeup 380 + // obs kse_create 381 + // obs kse_thr_interrupt 382 + // obs kse_release 383 + + // unimpl __mac_get_proc 384 + // unimpl __mac_set_proc 385 + // unimpl __mac_get_fd 386 + // unimpl __mac_get_file 387 + // unimpl __mac_set_fd 388 + // unimpl __mac_set_file 389 + BSDXY(__NR_kenv, sys_kenv), // 390 + BSDX_(__NR_lchflags, sys_lchflags), // 391 + + BSDXY(__NR_uuidgen, sys_uuidgen), // 392 + BSDXY(__NR_sendfile, sys_sendfile), // 393 + // unimpl mac_syscall 394 + +#if (FREEBSD_VERS >= FREEBSD_12) + BSDXY(__NR_freebsd11_getfsstat, sys_freebsd11_getfsstat), // 395 + BSDXY(__NR_freebsd11_statfs, sys_statfs), // 396 + BSDXY(__NR_freebsd11_fstatfs, sys_fstatfs), // 397 + BSDXY(__NR_freebsd11_fhstatfs, sys_fhstatfs), // 398 +#else + BSDXY(__NR_getfsstat, sys_getfsstat), // 395 + BSDXY(__NR_statfs, sys_statfs), // 396 + BSDXY(__NR_fstatfs, sys_fstatfs), // 397 + BSDXY(__NR_fhstatfs, sys_fhstatfs), // 398 +#endif + + // unimpl ksem_close 400 + // unimpl ksem_post 401 + // unimpl ksem_wait 402 + // unimpl ksem_trywait 403 + + // unimpl ksem_init 404 + // unimpl ksem_open 405 + // unimpl ksem_unlink 406 + // unimpl ksem_getvalue 407 + + // unimpl ksem_destroy 408 + // unimpl __mac_get_pid 409 + // unimpl __mac_get_link 410 + // unimpl __mac_set_link 411 + + BSDX_(__NR_extattr_set_link, sys_extattr_set_link), // 412 + BSDXY(__NR_extattr_get_link, sys_extattr_get_link), // 413 + BSDX_(__NR_extattr_delete_link, sys_extattr_delete_link), // 414 + // unimpl __mac_execve 415 + + BSDXY(__NR_sigaction, sys_sigaction), // 416 + BSDX_(__NR_sigreturn, sys_sigreturn), // 417 + + BSDXY(__NR_getcontext, sys_getcontext), // 421 + BSDX_(__NR_setcontext, sys_setcontext), // 422 + BSDXY(__NR_swapcontext, sys_swapcontext), // 423 + + BSDX_(__NR_swapoff, sys_swapoff), // 424 + BSDXY(__NR___acl_get_link, sys___acl_get_link), // 425 + BSDX_(__NR___acl_set_link, sys___acl_set_link), // 426 + BSDX_(__NR___acl_delete_link, sys___acl_delete_link), // 427 + + BSDX_(__NR___acl_aclcheck_link, sys___acl_aclcheck_link), // 428 + BSDXY(__NR_sigwait, sys_sigwait), // 429 + BSDX_(__NR_thr_create, sys_thr_create), // 430 + BSDX_(__NR_thr_exit, sys_thr_exit), // 431 + + BSDXY(__NR_thr_self, sys_thr_self), // 432 + BSDXY(__NR_thr_kill, sys_thr_kill), // 433 +#if (FREEBSD_VERS <= FREEBSD_10) + BSDXY(__NR__umtx_lock, sys__umtx_lock), // 434 + BSDXY(__NR__umtx_unlock, sys__umtx_unlock), // 435 +#endif + + BSDX_(__NR_jail_attach, sys_jail_attach), // 436 + BSDXY(__NR_extattr_list_fd, sys_extattr_list_fd), // 437 + BSDXY(__NR_extattr_list_file, sys_extattr_list_file), // 438 + BSDXY(__NR_extattr_list_link, sys_extattr_list_link), // 439 + + // obs kse_switchin 440 + // unimpl ksem_timedwait 441 + BSDX_(__NR_thr_suspend, sys_thr_suspend), // 442 + BSDX_(__NR_thr_wake, sys_thr_wake), // 443 + BSDX_(__NR_kldunloadf, sys_kldunloadf), // 444 + // unimpl audit 445 + // unimpl auditon 446 + // unimpl getauid 447 + + // unimpl setauid 448 + // unimpl getaudit 449 + // unimpl setaudit 450 + // unimpl getaudit_addr 451 + // unimpl setaudit_addr 452 + // unimpl auditctl 453 + BSDXY(__NR__umtx_op, sys__umtx_op), // 454 + BSDX_(__NR_thr_new, sys_thr_new), // 455 + + BSDX_(__NR_sigqueue, sys_sigqueue), // 456 + BSDXY(__NR_kmq_open, sys_kmq_open), // 457 + BSDX_(__NR_kmq_setattr, sys_kmq_setattr), // 458 + BSDXY(__NR_kmq_timedreceive, sys_kmq_timedreceive), // 459 + + BSDX_(__NR_kmq_timedsend, sys_kmq_timedsend), // 460 + BSDX_(__NR_kmq_notify, sys_kmq_notify), // 461 + BSDX_(__NR_kmq_unlink, sys_kmq_unlink), // 462 + BSDX_(__NR_abort2, sys_abort2), // 463 + + BSDX_(__NR_thr_set_name, sys_thr_set_name), // 464 + BSDX_(__NR_aio_fsync, sys_aio_fsync), // 465 + BSDXY(__NR_rtprio_thread, sys_rtprio_thread), // 466 + + // unimpl sctp_peeloff 471 + + // unimpl sctp_generic_sendmsg 472 + // unimpl sctp_generic_sendmsg_iov 473 + // unimpl sctp_generic_recvmsg 474 + BSDXY(__NR_pread, sys_pread), // 475 + + BSDX_(__NR_pwrite, sys_pwrite), // 476 + BSDX_(__NR_mmap, sys_mmap), // 477 + BSDX_(__NR_lseek, sys_lseek), // 478 + BSDX_(__NR_truncate, sys_truncate), // 479 + BSDX_(__NR_ftruncate, sys_ftruncate), // 480 + BSDXY(__NR_thr_kill2, sys_thr_kill2), // 481 + BSDXY(__NR_shm_open, sys_shm_open), // 482 + BSDX_(__NR_shm_unlink, sys_shm_unlink), // 483 + + BSDXY(__NR_cpuset, sys_cpuset), // 484 + BSDX_(__NR_cpuset_setid, sys_cpuset_setid), // 485 + BSDXY(__NR_cpuset_getid, sys_cpuset_getid), // 486 + + BSDXY(__NR_cpuset_getaffinity, sys_cpuset_getaffinity), // 487 + BSDX_(__NR_cpuset_setaffinity, sys_cpuset_setaffinity), // 488 + BSDX_(__NR_faccessat, sys_faccessat), // 489 + BSDX_(__NR_fchmodat, sys_fchmodat), // 490 + BSDX_(__NR_fchownat, sys_fchownat), // 491 + + BSDX_(__NR_fexecve, sys_fexecve), // 492 +#if (FREEBSD_VERS >= FREEBSD_12) + BSDXY(__NR_freebsd11_fstatat, sys_freebsd11_fstatat), // 493 +#else + BSDXY(__NR_fstatat, sys_fstatat), // 493 +#endif + BSDX_(__NR_futimesat, sys_futimesat), // 494 + BSDX_(__NR_linkat, sys_linkat), // 495 + + BSDX_(__NR_mkdirat, sys_mkdirat), // 496 + BSDX_(__NR_mkfifoat, sys_mkfifoat), // 497 + +#if (FREEBSD_VERS >= FREEBSD_12) + BSDX_(__NR_freebsd11_mknodat, sys_freebsd11_mknodat), // 498 +#else + BSDX_(__NR_mknodat, sys_mknodat), // 498 +#endif + + BSDXY(__NR_openat, sys_openat), // 499 + + BSDXY(__NR_readlinkat, sys_readlinkat), // 500 + BSDX_(__NR_renameat, sys_renameat), // 501 + BSDX_(__NR_symlinkat, sys_symlinkat), // 502 + BSDX_(__NR_unlinkat, sys_unlinkat), // 503 + + BSDX_(__NR_posix_openpt, sys_posix_openpt), // 504 + // unimp gssd_syscall 505 + BSDX_(__NR_jail_get, sys_jail_get), // 506 + BSDX_(__NR_jail_set, sys_jail_set), // 507 + BSDX_(__NR_jail_remove, sys_jail_remove), // 508 + BSDX_(__NR_closefrom, sys_closefrom), // 509 + BSDXY(__NR___semctl, sys___semctl), // 510 + BSDXY(__NR_msgctl, sys_msgctl), // 511 + BSDXY(__NR_shmctl, sys_shmctl), // 512 + BSDX_(__NR_lpathconf, sys_lpathconf), // 513 + /* 514 is obsolete cap_new */ + BSDXY(__NR___cap_rights_get, sys_cap_rights_get), // 515 + BSDX_(__NR_cap_enter, sys_cap_enter), // 516 + BSDXY(__NR_cap_getmode, sys_cap_getmode), // 517 + BSDXY(__NR_pdfork, sys_pdfork), // 518 + BSDX_(__NR_pdkill, sys_pdkill), // 519 + BSDXY(__NR_pdgetpid, sys_pdgetpid), // 520 + BSDXY(__NR_pselect, sys_pselect), // 522 + BSDXY(__NR_getloginclass, sys_getloginclass), // 523 + BSDX_(__NR_setloginclass, sys_setloginclass), // 524 + BSDXY(__NR_rctl_get_racct, sys_rctl_get_racct), // 525 + BSDXY(__NR_rctl_get_rules, sys_rctl_get_rules), // 526 + BSDXY(__NR_rctl_get_limits, sys_rctl_get_limits), // 527 + BSDXY(__NR_rctl_add_rule, sys_rctl_add_rule), // 528 + BSDXY(__NR_rctl_remove_rule, sys_rctl_remove_rule), // 529 + BSDX_(__NR_posix_fallocate, sys_posix_fallocate), // 530 + BSDX_(__NR_posix_fadvise, sys_posix_fadvise), // 531 + BSDXY(__NR_wait6, sys_wait6), // 532 + BSDX_(__NR_cap_rights_limit, sys_cap_rights_limit), // 533 + BSDX_(__NR_cap_ioctls_limit, sys_cap_ioctls_limit), // 534 + BSDXY(__NR_cap_ioctls_get, sys_cap_ioctls_get), // 535 + BSDX_(__NR_cap_fcntls_limit, sys_cap_fcntls_limit), // 536 + BSDXY(__NR_cap_fcntls_get, sys_cap_fcntls_get), // 537 + BSDX_(__NR_bindat, sys_bindat), // 538 + BSDX_(__NR_connectat, sys_connectat), // 539 + BSDX_(__NR_chflagsat, sys_chflagsat), // 540 + BSDXY(__NR_accept4, sys_accept4), // 541 + BSDXY(__NR_pipe2, sys_pipe2), // 542 + BSDX_(__NR_aio_mlock, sys_aio_mlock), // 543 + BSDXY(__NR_procctl, sys_procctl), // 544 + + // 544 is the highest syscall on FreeBSD 9 + +#if (FREEBSD_VERS >= FREEBSD_10) + + BSDXY(__NR_ppoll, sys_ppoll), // 545 + BSDX_(__NR_futimens, sys_futimens), // 546 + BSDX_(__NR_utimensat, sys_utimensat), // 547 + +#endif // FREEBSD_VERS >= FREEBSD_10 + +#if (FREEBSD_VERS >= FREEBSD_11) + + /* 548 is obsolete numa_getaffinity */ + /* 549 is obsolete numa_setaffinity */ + BSDX_(__NR_fdatasync, sys_fdatasync), // 550 + +#endif // FREEBSD_VERS >= FREEBSD_11 + +#if (FREEBSD_VERS >= FREEBSD_12) + BSDXY(__NR_fstat, sys_fstat), // 551 + BSDXY(__NR_fstatat, sys_fstatat), // 552 + BSDXY(__NR_fhstat, sys_fhstat), // 553 + BSDXY(__NR_getdirentries, sys_getdirentries), // 554 + BSDXY(__NR_statfs, sys_statfs), // 555 + BSDXY(__NR_fstatfs, sys_fstatfs), // 556 + BSDXY(__NR_getfsstat, sys_getfsstat), // 557 + BSDXY(__NR_fhstatfs, sys_fhstatfs), // 558 + BSDX_(__NR_mknodat, sys_mknodat), // 559 + BSDXY(__NR_kevent, sys_kevent), // 560 + BSDXY(__NR_cpuset_getdomain, sys_cpuset_getdomain), // 561 + BSDX_(__NR_cpuset_setdomain, sys_cpuset_setdomain), // 562 + BSDXY(__NR_getrandom, sys_getrandom), // 563 + BSDXY(__NR_getfhat, sys_getfhat), // 564 + BSDX_(__NR_fhlink, sys_fhlink), // 565 + BSDX_(__NR_fhlinkat, sys_fhlinkat), // 566 + BSDXY(__NR_fhreadlink, sys_fhreadlink), // 567 +#endif // FREEBSD_VERS >= FREEBSD_12 + +#if (FREEBSD_VERS >= FREEBSD_12_2) + // unimpl __NR_funlinkat 568 + // unimpl __NR_copy_file_range 569 + BSDXY(__NR___sysctlbyname, sys___sysctlbyname), // 570 + // unimpl __NR_shm_open2 571 + // unimpl __NR_shm_rename 572 + // unimpl __NR_sigfastblock 573 + // unimpl __NR___realpathat 574 + // unimpl __NR_close_range 575 +#endif + +#if (FREEBSD_VERS >= FREEBSD_13) + // unimpl __NR_rpctls_syscall 576 +#endif + +#if (FREEBSD_VERS >= FREEBSD_14) + // unimpl __NR___specialfd 577 + // unimpl __NR_aio_writev 578 + // unimpl __NR_aio_readv 579 +#endif + + BSDX_(__NR_fake_sigreturn, sys_fake_sigreturn), // 1000, fake sigreturn + +}; + +const SyscallTableEntry* ML_(get_freebsd_syscall_entry) ( UInt sysno ) +{ + const UInt syscall_table_size + = sizeof(ML_(syscall_table)) / sizeof(ML_(syscall_table)[0]); + + /* Is it in the contiguous initial section of the table? */ + if (sysno < syscall_table_size) { + const SyscallTableEntry* sys = &ML_(syscall_table)[sysno]; + if (sys->before == NULL) + return NULL; /* no entry */ + else + return sys; + } + + /* Can't find a wrapper */ + return NULL; +} + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ + +#endif // defined(VGO_freebsd) diff --git a/coregrind/m_syswrap/syswrap-x86-freebsd.c b/coregrind/m_syswrap/syswrap-x86-freebsd.c new file mode 100644 index 0000000000..d65d0100c4 --- /dev/null +++ b/coregrind/m_syswrap/syswrap-x86-freebsd.c @@ -0,0 +1,1517 @@ + +/*--------------------------------------------------------------------*/ +/*--- Platform-specific syscalls stuff. syswrap-x86-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2008 Nicholas Nethercote + njn@valgrind.org + Copyright (C) 2018-2021 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_x86_freebsd) + +/* TODO/FIXME jrs 20050207: assignments to the syscall return result + in interrupted_syscall() need to be reviewed. They don't seem + to assign the shadow state. +*/ + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_vkiscnums.h" +#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy +#include "pub_core_threadstate.h" +#include "pub_core_aspacemgr.h" +#include "pub_core_debuglog.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcprint.h" +#include "pub_core_libcproc.h" +#include "pub_core_libcsignal.h" +#include "pub_core_machine.h" +#include "pub_core_mallocfree.h" +#include "pub_core_options.h" +#include "pub_core_scheduler.h" +#include "pub_core_sigframe.h" // For VG_(sigframe_destroy)() +#include "pub_core_signals.h" +#include "pub_core_syscall.h" +#include "pub_core_syswrap.h" +#include "pub_core_tooliface.h" +#include "pub_core_stacks.h" // VG_(register_stack) + +#include "priv_types_n_macros.h" +#include "priv_syswrap-generic.h" /* for decls of generic wrappers */ +#include "priv_syswrap-freebsd.h" /* for decls of linux-ish wrappers */ +#include "priv_syswrap-main.h" + +/* --------------------------------------------------------------------- + clone() handling + ------------------------------------------------------------------ */ + +/* Call f(arg1), but first switch stacks, using 'stack' as the new + stack, and use 'retaddr' as f's return-to address. Also, clear all + the integer registers before entering f.*/ +__attribute__((noreturn)) +void ML_(call_on_new_stack_0_1) ( Addr stack, + Addr retaddr, + void (*f)(Word), + Word arg1 ); +// 4(%esp) == stack +// 8(%esp) == retaddr +// 12(%esp) == f +// 16(%esp) == arg1 +asm( + ".text\n" + ".globl vgModuleLocal_call_on_new_stack_0_1\n" + "vgModuleLocal_call_on_new_stack_0_1:\n" + " movl %esp, %esi\n" // remember old stack pointer + " movl 4(%esi), %esp\n" // set stack + " pushl 16(%esi)\n" // arg1 to stack + " pushl 8(%esi)\n" // retaddr to stack + " pushl 12(%esi)\n" // f to stack + " movl $0, %eax\n" // zero all GP regs + " movl $0, %ebx\n" + " movl $0, %ecx\n" + " movl $0, %edx\n" + " movl $0, %esi\n" + " movl $0, %edi\n" + " movl $0, %ebp\n" + " ret\n" // jump to f + " ud2\n" // should never get here + ".previous\n" +); + + +#if 0 +/* + Perform a rfork system call. rfork is strange because it has + fork()-like return-twice semantics, so it needs special + handling here. + + Upon entry, we have: + + int (fn)(void*) in 0+FSZ(%esp) + void* child_stack in 4+FSZ(%esp) + int flags in 8+FSZ(%esp) + void* arg in 12+FSZ(%esp) + pid_t* child_tid in 16+FSZ(%esp) + pid_t* parent_tid in 20+FSZ(%esp) + void* tls_ptr in 24+FSZ(%esp) + + System call requires: + + int $__NR_clone in %eax + int flags in %ebx + void* child_stack in %ecx + pid_t* parent_tid in %edx + pid_t* child_tid in %edi + void* tls_ptr in %esi + + Returns an Int encoded in the linux-x86 way, not a SysRes. + */ +#define FSZ "4+4+4+4" /* frame size = retaddr+ebx+edi+esi */ +#define __NR_CLONE VG_STRINGIFY(__NR_clone) +#define __NR_EXIT VG_STRINGIFY(__NR_exit) + +extern +Int do_syscall_clone_x86_freebsd ( Word (*fn)(void *), + void* stack, + Int flags, + void* arg, + Int* child_tid, + Int* parent_tid, + vki_modify_ldt_t * ); +asm( + ".text\n" + "do_syscall_clone_x86_freebsd:\n" + " push %ebx\n" + " push %edi\n" + " push %esi\n" + + /* set up child stack with function and arg */ + " movl 4+"FSZ"(%esp), %ecx\n" /* syscall arg2: child stack */ + " movl 12+"FSZ"(%esp), %ebx\n" /* fn arg */ + " movl 0+"FSZ"(%esp), %eax\n" /* fn */ + " lea -8(%ecx), %ecx\n" /* make space on stack */ + " movl %ebx, 4(%ecx)\n" /* fn arg */ + " movl %eax, 0(%ecx)\n" /* fn */ + + /* get other args to clone */ + " movl 8+"FSZ"(%esp), %ebx\n" /* syscall arg1: flags */ + " movl 20+"FSZ"(%esp), %edx\n" /* syscall arg3: parent tid * */ + " movl 16+"FSZ"(%esp), %edi\n" /* syscall arg5: child tid * */ + " movl 24+"FSZ"(%esp), %esi\n" /* syscall arg4: tls_ptr * */ + " movl $"__NR_CLONE", %eax\n" + " int $0x80\n" /* clone() */ + " testl %eax, %eax\n" /* child if retval == 0 */ + " jnz 1f\n" + + /* CHILD - call thread function */ + " popl %eax\n" + " call *%eax\n" /* call fn */ + + /* exit with result */ + " movl %eax, %ebx\n" /* arg1: return value from fn */ + " movl $"__NR_EXIT", %eax\n" + " int $0x80\n" + + /* Hm, exit returned */ + " ud2\n" + + "1:\n" /* PARENT or ERROR */ + " pop %esi\n" + " pop %edi\n" + " pop %ebx\n" + " ret\n" + ".previous\n" +); + +#undef FSZ +#undef __NR_CLONE +#undef __NR_EXIT + + +// forward declarations +static void setup_child ( ThreadArchState*, ThreadArchState*, Bool ); + +/* + When a client clones, we need to keep track of the new thread. This means: + 1. allocate a ThreadId+ThreadState+stack for the the thread + + 2. initialize the thread's new VCPU state + + 3. create the thread using the same args as the client requested, + but using the scheduler entrypoint for EIP, and a separate stack + for ESP. + */ +static SysRes do_rfork ( ThreadId ptid, + UInt flags) +{ + static const Bool debug = False; + + Addr esp; + ThreadId ctid = VG_(alloc_ThreadState)(); + ThreadState* ptst = VG_(get_ThreadState)(ptid); + ThreadState* ctst = VG_(get_ThreadState)(ctid); + UWord* stack; + NSegment const* seg; + SysRes res; + Int eax; + vki_sigset_t blockall, savedmask; + + VG_(sigfillset)(&blockall); + + vg_assert(VG_(is_running_thread)(ptid)); + vg_assert(VG_(is_valid_tid)(ctid)); + + stack = (UWord*)ML_(allocstack)(ctid); + if (stack == NULL) { + res = VG_(mk_SysRes_Error)( VKI_ENOMEM ); + goto out; + } + + /* Copy register state + + Both parent and child return to the same place, and the code + following the clone syscall works out which is which, so we + don't need to worry about it. + + The parent gets the child's new tid returned from clone, but the + child gets 0. + + If the clone call specifies a NULL esp for the new thread, then + it actually gets a copy of the parent's esp. + */ + /* Note: the clone call done by the Quadrics Elan3 driver specifies + clone flags of 0xF00, and it seems to rely on the assumption + that the child inherits a copy of the parent's GDT. + setup_child takes care of setting that up. */ + setup_child( &ctst->arch, &ptst->arch, True ); + + /* Make sys_clone appear to have returned Success(0) in the + child. */ + ctst->arch.vex.guest_EAX = 0; + + /* Assume linuxthreads port storing its intended stack in %esi */ + esp = ctst->arch.vex.guest_ESI; + + ctst->os_state.parent = ptid; + + /* inherit signal mask */ + ctst->sig_mask = ptst->sig_mask; + ctst->tmp_sig_mask = ptst->sig_mask; + + /* We don't really know where the client stack is, because its + allocated by the client. The best we can do is look at the + memory mappings and try to derive some useful information. We + assume that esp starts near its highest possible value, and can + only go down to the start of the mmaped segment. */ + seg = VG_(am_find_nsegment)((Addr)esp); + if (seg && seg->kind != SkResvn) { + ctst->client_stack_highest_byte = (Addr)VG_PGROUNDUP(esp); + ctst->client_stack_szB = ctst->client_stack_highest_byte - seg->start; + + ctst->os_state.stk_id = VG_(register_stack)(seg->start, ctst->client_stack_highest_byte); + + if (debug) + VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n", + ctid, seg->start, VG_PGROUNDUP(esp)); + } else { + VG_(message)(Vg_UserMsg, "!? New thread %d starts with ESP(%#lx) unmapped\n", + ctid, esp); + ctst->client_stack_szB = 0; + } + + /* Assume the clone will succeed, and tell any tool that wants to + know that this thread has come into existence. We cannot defer + it beyond this point because sys_set_thread_area, just below, + causes tCheck to assert by making references to the new ThreadId + if we don't state the new thread exists prior to that point. + If the clone fails, we'll send out a ll_exit notification for it + at the out: label below, to clean up. */ + VG_TRACK ( pre_thread_ll_create, ptid, ctid ); + + /* start the thread with everything blocked */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask); + + /* Create the new thread */ + /* XXX need to see what happens with tids etc with rfork */ + eax = do_syscall_clone_x86_freebsd( + ML_(start_thread_NORETURN), stack, flags /*, &VG_(threads)[ctid], NULL*/ ); + res = VG_(mk_SysRes_x86_freebsd)( eax ); /* XXX edx returns too! */ + + VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL); + +out: + if (res.isError) { + /* clone failed */ + VG_(cleanup_thread)(&ctst->arch); + ctst->status = VgTs_Empty; + /* oops. Better tell the tool the thread exited in a hurry :-) */ + VG_TRACK( pre_thread_ll_exit, ctid ); + } + + return res; +} +#endif + +/* Translate a struct modify_ldt_ldt_s to a VexGuestX86SegDescr */ + +static +void translate_to_hw_format ( /* IN */ void* base, + /* OUT */ VexGuestX86SegDescr* out) +{ + UInt entry_1, entry_2; + UInt base_addr = (UInt) base; + vg_assert(8 == sizeof(VexGuestX86SegDescr)); + + if (0) + VG_(printf)("translate_to_hw_format: base %p\n", base ); + + /* Allow LDTs to be cleared by the user. */ + if (base == 0) { + entry_1 = 0; + entry_2 = 0; + goto install; + } + /* base as specified, no limit, read/write/accessed etc */ + entry_1 = ((base_addr & 0x0000ffff) << 16) | 0x0ffff; + entry_2 = (base_addr & 0xff000000) | + ((base_addr & 0x00ff0000) >> 16) | 0x00cff300; + + /* Install the new entry ... */ +install: + out->LdtEnt.Words.word1 = entry_1; + out->LdtEnt.Words.word2 = entry_2; +} + +/* Create a zeroed-out GDT. */ +static VexGuestX86SegDescr* alloc_zeroed_x86_GDT ( void ) +{ + Int nbytes = VEX_GUEST_X86_GDT_NENT * sizeof(VexGuestX86SegDescr); + return VG_(arena_calloc)(VG_AR_CORE, "di.syswrap-x86.azxG.1", nbytes, 1); +} + +#if 0 +/* Create a zeroed-out LDT. */ +static VexGuestX86SegDescr* alloc_zeroed_x86_LDT ( void ) +{ + Int nbytes = VEX_GUEST_X86_LDT_NENT * sizeof(VexGuestX86SegDescr); + return VG_(arena_calloc)(VG_AR_CORE, "di.syswrap-x86.azxL.1", nbytes, 1); +} + +/* Free up an LDT or GDT allocated by the above fns. */ +static void free_LDT_or_GDT ( VexGuestX86SegDescr* dt ) +{ + vg_assert(dt); + VG_(arena_free)(VG_AR_CORE, (void*)dt); +} + +/* Copy contents between two existing LDTs. */ +static void copy_LDT_from_to ( VexGuestX86SegDescr* src, + VexGuestX86SegDescr* dst ) +{ + Int i; + vg_assert(src); + vg_assert(dst); + for (i = 0; i < VEX_GUEST_X86_LDT_NENT; i++) + dst[i] = src[i]; +} + +/* Copy contents between two existing GDTs. */ +static void copy_GDT_from_to ( VexGuestX86SegDescr* src, + VexGuestX86SegDescr* dst ) +{ + Int i; + vg_assert(src); + vg_assert(dst); + for (i = 0; i < VEX_GUEST_X86_GDT_NENT; i++) + dst[i] = src[i]; +} + +/* Free this thread's DTs, if it has any. */ +static void deallocate_LGDTs_for_thread ( VexGuestX86State* vex ) +{ + vg_assert(sizeof(HWord) == sizeof(void*)); + + if (0) + VG_(printf)("deallocate_LGDTs_for_thread: " + "ldt = 0x%x, gdt = 0x%x\n", + vex->guest_LDT, vex->guest_GDT ); + + if (vex->guest_LDT != (HWord)NULL) { + free_LDT_or_GDT( (VexGuestX86SegDescr*)vex->guest_LDT ); + vex->guest_LDT = (HWord)NULL; + } + + if (vex->guest_GDT != (HWord)NULL) { + free_LDT_or_GDT( (VexGuestX86SegDescr*)vex->guest_GDT ); + vex->guest_GDT = (HWord)NULL; + } +} +#endif + +static SysRes sys_set_thread_area ( ThreadId tid, Int *idxptr, void *base) +{ + VexGuestX86SegDescr* gdt; + Int idx; + + vg_assert(8 == sizeof(VexGuestX86SegDescr)); + vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*)); + + gdt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_GDT; + + /* If the thread doesn't have a GDT, allocate it now. */ + if (!gdt) { + gdt = alloc_zeroed_x86_GDT(); + VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt; + } + + idx = *idxptr; + if (idx == -1) { + /* Find and use the first free entry. Don't allocate entry + zero, because the hardware will never do that, and apparently + doing so confuses some code (perhaps stuff running on + Wine). */ + for (idx = 1; idx < VEX_GUEST_X86_GDT_NENT; idx++) { + if (gdt[idx].LdtEnt.Words.word1 == 0 + && gdt[idx].LdtEnt.Words.word2 == 0) + break; + } + + if (idx == VEX_GUEST_X86_GDT_NENT) + return VG_(mk_SysRes_Error)( VKI_ESRCH ); + } else if (idx < 0 || idx == 0 || idx >= VEX_GUEST_X86_GDT_NENT) { + /* Similarly, reject attempts to use GDT[0]. */ + return VG_(mk_SysRes_Error)( VKI_EINVAL ); + } + + translate_to_hw_format(base, &gdt[idx]); + + *idxptr = idx; + return VG_(mk_SysRes_Success)( 0 ); +} + +static SysRes sys_get_thread_area ( ThreadId tid, Int idx, void ** basep ) +{ + VexGuestX86SegDescr* gdt; + UInt base; + + vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*)); + vg_assert(8 == sizeof(VexGuestX86SegDescr)); + + gdt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_GDT; + + /* If the thread doesn't have a GDT, allocate it now. */ + if (!gdt) { + gdt = alloc_zeroed_x86_GDT(); + VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt; + } + + base = ( gdt[idx].LdtEnt.Bits.BaseHi << 24 ) | + ( gdt[idx].LdtEnt.Bits.BaseMid << 16 ) | + gdt[idx].LdtEnt.Bits.BaseLow; + *basep = (void *)base; + + return VG_(mk_SysRes_Success)( 0 ); +} + +/* --------------------------------------------------------------------- + More thread stuff + ------------------------------------------------------------------ */ + +void VG_(cleanup_thread) ( ThreadArchState* arch ) +{ +} + + +/* --------------------------------------------------------------------- + PRE/POST wrappers for x86/FreeBSD-specific syscalls + ------------------------------------------------------------------ */ + +#define PRE(name) DEFN_PRE_TEMPLATE(freebsd, name) +#define POST(name) DEFN_POST_TEMPLATE(freebsd, name) + +// SYS_sysarch 165 +// int sysarch(int number, void *args); +PRE(sys_sysarch) +{ + ThreadState *tst; + Int idx; + void **p; + + PRINT("sys_sysarch ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2); + PRE_REG_READ2(int, "sysarch", int, number, void *, args); + switch (ARG1) { + case VKI_I386_SET_GSBASE: + PRINT("sys_i386_set_gsbase ( %#lx )", ARG2); + + if (ML_(safe_to_deref)((void**)ARG2, sizeof(void*))) { + /* On FreeBSD, the syscall loads the %gs selector for us, so do it now. */ + tst = VG_(get_ThreadState)(tid); + p = (void**)ARG2; + tst->arch.vex.guest_GS = (1 << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */ + /* "do" the syscall ourselves; the kernel never sees it */ + idx = 1; + SET_STATUS_from_SysRes( sys_set_thread_area( tid, &idx, *p ) ); + } else { + // ???? + SET_STATUS_Failure( VKI_EINVAL ); + } + + break; + case VKI_I386_GET_GSBASE: + PRINT("sys_i386_get_gsbase ( %#lx )", ARG2); + PRE_MEM_WRITE( "i386_get_gsbase(basep)", ARG2, sizeof(void *) ); + if (ML_(safe_to_deref)((void**)ARG2, sizeof(void*))) { + /* "do" the syscall ourselves; the kernel never sees it */ + SET_STATUS_from_SysRes( sys_get_thread_area( tid, 2, (void **)ARG2 ) ); + } else { + SET_STATUS_Failure( VKI_EINVAL ); + } + break; + case VKI_I386_GET_XFPUSTATE: + PRINT("sys_i386_get_xfpustate ( %#lx )", ARG2); + PRE_MEM_WRITE( "i386_get_xfpustate(basep)", ARG2, sizeof(void *) ); + /* "do" the syscall ourselves; the kernel never sees it */ + tst = VG_(get_ThreadState)(tid); + SET_STATUS_Success2( tst->arch.vex.guest_FPTAG[0], tst->arch.vex.guest_FPTAG[0] ); + break; + default: + VG_(message) (Vg_UserMsg, "unhandled sysarch cmd %lu", ARG1); + VG_(unimplemented) ("unhandled sysarch cmd"); + break; + } +} + +POST(sys_sysarch) +{ + switch (ARG1) { + case VKI_AMD64_SET_FSBASE: + break; + case VKI_AMD64_GET_FSBASE: + POST_MEM_WRITE( ARG2, sizeof(void *) ); + break; + case VKI_AMD64_GET_XFPUSTATE: + POST_MEM_WRITE( ARG2, sizeof(void *) ); + break; + default: + break; + } +} + +// freebsd6_pread 173 +#if (FREEBSD_VERS <= FREEBSD_10) +PRE(sys_freebsd6_pread) +{ + *flags |= SfMayBlock; + PRINT("sys_freebsd6_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG5, ARG6); + PRE_REG_READ6(ssize_t, "pread", + unsigned int, fd, char *, buf, vki_size_t, count, + int, pad, unsigned int, off_low, unsigned int, off_high); + + if (!ML_(fd_allowed)(ARG1, "freebsd6_pread", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_WRITE( "freebsd6_pread(buf)", ARG2, ARG3 ); +} + +POST(sys_freebsd6_pread) +{ + vg_assert(SUCCESS); + POST_MEM_WRITE( ARG2, RES ); +} +#endif + +// freebsd6_pwrite 174 +#if (FREEBSD_VERS <= FREEBSD_10) +PRE(sys_freebsd6_pwrite) +{ + Bool ok; + *flags |= SfMayBlock; + PRINT("sys_freebsd6_pwrite ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG5, ARG6); + PRE_REG_READ6(ssize_t, "freebsd6_pwrite", + unsigned int, fd, const char *, buf, vki_size_t, count, + int, pad, unsigned int, off_low, unsigned int, off_high); + /* check to see if it is allowed. If not, try for an exemption from + --sim-hints=enable-outer (used for self hosting). */ + ok = ML_(fd_allowed)(ARG1, "freebsd6_pwrite", tid, False); + if (!ok && ARG1 == 2/*stderr*/ + && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints))) + ok = True; + if (!ok) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_READ( "freebsd6_write(buf)", ARG2, ARG3 ); +} +#endif + +// SYS_freebsd6_mmap 197 +#if (FREEBSD_VERS <= FREEBSD_10) +/* This is here because on x86 the off_t is passed in 2 regs. Don't ask about pad. */ + +/* caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); */ +/* ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7+ARG8 */ + +PRE(sys_freebsd6_mmap) +{ + SysRes r; + + PRINT("sys_freebsd6_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, pad%" FMT_REGWORD "u, lo0x%" FMT_REGWORD "x hi0x%" FMT_REGWORD "x)", + ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8 ); + PRE_REG_READ8(long, "mmap", + char *, addr, unsigned long, len, int, prot, int, flags, + int, fd, int, pad, unsigned long, lo, unsigned long, hi); + + r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, MERGE64(ARG7,ARG8) ); + SET_STATUS_from_SysRes(r); +} +#endif + +// freebsd6_lseek 199 +#if (FREEBSD_VERS <= FREEBSD_10) +PRE(sys_freebsd6_lseek) +{ + PRINT("sys_freebsd6_lseek ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG3,ARG4,ARG5); + PRE_REG_READ5(long, "lseek", + unsigned int, fd, int, pad, unsigned int, offset_low, + unsigned int, offset_high, unsigned int, whence); +} +#endif + +// freebsd6_truncate 200 +#if (FREEBSD_VERS <= FREEBSD_10) +PRE(sys_freebsd6_truncate) +{ + *flags |= SfMayBlock; + PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG3,ARG4); + PRE_REG_READ4(long, "truncate", + const char *, path, int, pad, + unsigned int, length_low, unsigned int, length_high); + PRE_MEM_RASCIIZ( "truncate(path)", ARG1 ); +} +#endif + +// freebsd6_ftruncate 201 +#if (FREEBSD_VERS <= FREEBSD_10) +PRE(sys_freebsd6_ftruncate) +{ + *flags |= SfMayBlock; + PRINT("sys_ftruncate ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG3,ARG4); + PRE_REG_READ4(long, "ftruncate", unsigned int, fd, int, pad, + unsigned int, length_low, unsigned int, length_high); +} +#endif + +// SYS_rfork 251 +// pid_t rfork(int flags); +PRE(sys_rfork) +{ + PRINT("sys_rfork ( %" FMT_REGWORD "x )",ARG1); + PRE_REG_READ1(int, "rfork", + unsigned int, flags); + +#if 0 + cloneflags = ARG1; + + if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) { + SET_STATUS_Failure( VKI_EINVAL ); + return; + } + + SET_STATUS_from_SysRes( do_clone(tid, ARG1)); + + if (SUCCESS) { + *flags |= SfYieldAfter; + } +#else + VG_(message)(Vg_UserMsg, "fork() not implemented"); + VG_(unimplemented)("Valgrind does not support rfork() yet."); + SET_STATUS_Failure( VKI_ENOSYS ); +#endif +} + +// SYS_preadv 289 +// ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); +PRE(sys_preadv) +{ + Int i; + struct vki_iovec * vec; + *flags |= SfMayBlock; + PRINT("sys_preadv ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" + FMT_REGWORD "d, %llu )", SARG1, ARG2, SARG3, MERGE64(ARG4,ARG5)); + PRE_REG_READ5(ssize_t, "preadv", + int, fd, const struct iovec *, iovr, + int, iovcnt, vki_uint32_t, MERGE64_FIRST(offset), + vki_uint32_t, MERGE64_SECOND(offset)); + if (!ML_(fd_allowed)(ARG1, "preadv", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } else { + if ((Int)ARG3 >= 0) + PRE_MEM_READ( "preadv(iov)", ARG2, ARG3 * sizeof(struct vki_iovec) ); + + if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) { + vec = (struct vki_iovec *)(Addr)ARG2; + for (i = 0; i < (Int)ARG3; i++) + PRE_MEM_WRITE( "preadv(iov[...])", + (Addr)vec[i].iov_base, vec[i].iov_len ); + } + } +} + +POST(sys_preadv) +{ + vg_assert(SUCCESS); + if (RES > 0) { + Int i; + struct vki_iovec * vec = (struct vki_iovec *)(Addr)ARG2; + Int remains = RES; + + /* RES holds the number of bytes read. */ + for (i = 0; i < (Int)ARG3; i++) { + Int nReadThisBuf = vec[i].iov_len; + if (nReadThisBuf > remains) nReadThisBuf = remains; + POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf ); + remains -= nReadThisBuf; + if (remains < 0) VG_(core_panic)("preadv: remains < 0"); + } + } +} + +// SYS_pwritev 290 +// ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); +PRE(sys_pwritev) +{ + Int i; + struct vki_iovec * vec; + *flags |= SfMayBlock; + PRINT("sys_pwritev ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" + FMT_REGWORD "d, %llu )", SARG1, ARG2, SARG3, MERGE64(ARG4,ARG5)); + + PRE_REG_READ5(ssize_t, "pwritev", + int, fd, const struct iovec *, iov, + int, iovcnt, + vki_uint32_t, MERGE64_FIRST(offset), + vki_uint32_t, MERGE64_SECOND(offset)); + if (!ML_(fd_allowed)(ARG1, "pwritev", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } else { + if ((Int)ARG3 >= 0) + PRE_MEM_READ( "pwritev(vector)", ARG2, ARG3 * sizeof(struct vki_iovec) ); + if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) { + vec = (struct vki_iovec *)(Addr)ARG2; + for (i = 0; i < (Int)ARG3; i++) + PRE_MEM_READ( "pwritev(iov[...])", + (Addr)vec[i].iov_base, vec[i].iov_len ); + } + } +} + +// SYS_sendfile 393 +// int sendfile(int fd, int s, off_t offset, size_t nbytes, +// struct sf_hdtr *hdtr, off_t *sbytes, int flags); +PRE(sys_sendfile) +{ + *flags |= SfMayBlock; + PRINT("sys_sendfile ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )", + SARG1,SARG2,LOHI64(ARG3,ARG4),ARG5,ARG6,ARG7,SARG8); + PRE_REG_READ8(int, "sendfile", + int, fd, int, s, unsigned int, offset_low, + unsigned int, offset_high, size_t, nbytes, + void *, hdtr, vki_off_t *, sbytes, int, flags); + + if (ARG6 != 0) + PRE_MEM_READ("sendfile(hdtr)", ARG6, sizeof(struct vki_sf_hdtr)); + + if (ARG7 != 0) + PRE_MEM_WRITE( "sendfile(sbytes)", ARG7, sizeof(vki_off_t) ); +} + +POST(sys_sendfile) +{ + if (ARG7 != 0 ) { + POST_MEM_WRITE( ARG7, sizeof( vki_off_t ) ); + } +} + +// SYS_sigreturn 417 +// int sigreturn(const ucontext_t *scp); +PRE(sys_sigreturn) +{ + PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "sigreturn", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); +} + + +static void restore_mcontext(ThreadState *tst, struct vki_mcontext *sc) +{ + tst->arch.vex.guest_EAX = sc->eax; + tst->arch.vex.guest_ECX = sc->ecx; + tst->arch.vex.guest_EDX = sc->edx; + tst->arch.vex.guest_EBX = sc->ebx; + tst->arch.vex.guest_EBP = sc->ebp; + tst->arch.vex.guest_ESP = sc->esp; + tst->arch.vex.guest_ESI = sc->esi; + tst->arch.vex.guest_EDI = sc->edi; + tst->arch.vex.guest_EIP = sc->eip; + tst->arch.vex.guest_CS = sc->cs; + tst->arch.vex.guest_SS = sc->ss; + tst->arch.vex.guest_DS = sc->ds; + tst->arch.vex.guest_ES = sc->es; + tst->arch.vex.guest_FS = sc->fs; + tst->arch.vex.guest_GS = sc->gs; + /* + * XXX: missing support for other flags. + */ + if (sc->eflags & 0x0001) + LibVEX_GuestX86_put_eflag_c(1, &tst->arch.vex); + else + LibVEX_GuestX86_put_eflag_c(0, &tst->arch.vex); +} + +static void fill_mcontext(ThreadState *tst, struct vki_mcontext *sc) +{ + sc->eax = tst->arch.vex.guest_EAX; + sc->ecx = tst->arch.vex.guest_ECX; + sc->edx = tst->arch.vex.guest_EDX; + sc->ebx = tst->arch.vex.guest_EBX; + sc->ebp = tst->arch.vex.guest_EBP; + sc->esp = tst->arch.vex.guest_ESP; + sc->esi = tst->arch.vex.guest_ESI; + sc->edi = tst->arch.vex.guest_EDI; + sc->eip = tst->arch.vex.guest_EIP; + sc->cs = tst->arch.vex.guest_CS; + sc->ss = tst->arch.vex.guest_SS; + sc->ds = tst->arch.vex.guest_DS; + sc->es = tst->arch.vex.guest_ES; + sc->fs = tst->arch.vex.guest_FS; + sc->gs = tst->arch.vex.guest_GS; + sc->eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex); + /* + not yet. + VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate)); + */ + sc->fpformat = VKI_FPFMT_NODEV; + sc->ownedfp = VKI_FPOWNED_NONE; + sc->len = sizeof(*sc); + VG_(memset)(sc->spare2, 0, sizeof(sc->spare2)); +} + +// SYS_getcontext 421 +// int getcontext(ucontext_t *ucp); +PRE(sys_getcontext) +{ + ThreadState* tst; + struct vki_ucontext *uc; + + PRINT("sys_getcontext ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(int, "getcontext", + struct vki_ucontext *, ucp); + PRE_MEM_WRITE( "getcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + uc = (struct vki_ucontext *)ARG1; + if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext))) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + tst = VG_(get_ThreadState)(tid); + fill_mcontext(tst, &uc->uc_mcontext); + uc->uc_mcontext.eax = 0; + uc->uc_mcontext.edx = 0; + uc->uc_mcontext.eflags &= ~0x0001; /* PSL_C */ + uc->uc_sigmask = tst->sig_mask; + VG_(memset)(uc->__spare__, 0, sizeof(uc->__spare__)); + SET_STATUS_Success(0); +} + +// SYS_setcontext 422 +// int setcontext(const ucontext_t *ucp); +PRE(sys_setcontext) +{ + ThreadState* tst; + struct vki_ucontext *uc; + + PRINT("sys_setcontext ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(long, "setcontext", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(tid >= 1 && tid < VG_N_THREADS); + vg_assert(VG_(is_running_thread)(tid)); + + tst = VG_(get_ThreadState)(tid); + uc = (struct vki_ucontext *)ARG1; + if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext)) || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + + restore_mcontext(tst, &uc->uc_mcontext); + tst->sig_mask = uc->uc_sigmask; + tst->tmp_sig_mask = uc->uc_sigmask; + + /* Tell the driver not to update the guest state with the "result", + and set a bogus result to keep it happy. */ + *flags |= SfNoWriteResult; + SET_STATUS_Success(0); + + /* Check to see if some any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + +// SYS_swapcontext 423 +// int swapcontext(ucontext_t *oucp, const ucontext_t *ucp); +PRE(sys_swapcontext) +{ + struct vki_ucontext *ucp, *oucp; + ThreadState* tst; + + PRINT("sys_swapcontext ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2); + PRE_REG_READ2(long, "swapcontext", + struct vki_ucontext *, oucp, struct vki_ucontext *, ucp); + + PRE_MEM_READ( "swapcontext(ucp)", ARG2, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "swapcontext(oucp)", ARG1, sizeof(struct vki_ucontext) ); + + oucp = (struct vki_ucontext *)ARG1; + ucp = (struct vki_ucontext *)ARG2; + if (!ML_(safe_to_deref)(oucp, sizeof(struct vki_ucontext)) || + !ML_(safe_to_deref)(ucp, sizeof(struct vki_ucontext)) || + ucp->uc_mcontext.len != sizeof(ucp->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + tst = VG_(get_ThreadState)(tid); + + /* + * Save the context. + */ + fill_mcontext(tst, &oucp->uc_mcontext); + oucp->uc_mcontext.eax = 0; + oucp->uc_mcontext.edx = 0; + oucp->uc_mcontext.eflags &= ~0x0001; /* PSL_C */ + oucp->uc_sigmask = tst->sig_mask; + VG_(memset)(oucp->__spare__, 0, sizeof(oucp->__spare__)); + + /* + * Switch to new one. + */ + restore_mcontext(tst, &ucp->uc_mcontext); + tst->sig_mask = ucp->uc_sigmask; + tst->tmp_sig_mask = ucp->uc_sigmask; + + /* Tell the driver not to update the guest state with the "result", + and set a bogus result to keep it happy. */ + *flags |= SfNoWriteResult; + SET_STATUS_Success(0); + + /* Check to see if some any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + +// SYS_thr_new 455 +// int thr_new(struct thr_param *param, int param_size); +PRE(sys_thr_new) +{ + static const Bool debug = False; + + ThreadId ctid = VG_(alloc_ThreadState)(); + ThreadState* ptst = VG_(get_ThreadState)(tid); + ThreadState* ctst = VG_(get_ThreadState)(ctid); + SysRes res; + vki_sigset_t blockall, savedmask; + struct vki_thr_param tp; + Int idx = -1; + Addr stk; + + PRINT("thr_new ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2); + PRE_REG_READ2(int, "thr_new", + struct thr_param *, param, + int, param_size); + + PRE_MEM_READ( "thr_new(param)", ARG1, offsetof(struct vki_thr_param, spare)); + if (!ML_(safe_to_deref)( (void*)ARG1, offsetof(struct vki_thr_param, spare))) { + SET_STATUS_Failure( VKI_EFAULT ); + return; + } + VG_(memset)(&tp, 0, sizeof(tp)); + VG_(memcpy)(&tp, (void *)ARG1, offsetof(struct vki_thr_param, spare)); + PRE_MEM_WRITE("clone(parent_tidptr)", (Addr)tp.parent_tid, sizeof(long)); + PRE_MEM_WRITE("clone(child_tidptr)", (Addr)tp.child_tid, sizeof(long)); + + VG_(sigfillset)(&blockall); + + vg_assert(VG_(is_running_thread)(tid)); + vg_assert(VG_(is_valid_tid)(ctid)); + + /* Copy register state + + On linux, both parent and child return to the same place, and the code + following the clone syscall works out which is which, so we + don't need to worry about it. + On FreeBSD, thr_new arranges a direct call. We don't actually need any + of this gunk. + + The parent gets the child's new tid returned from clone, but the + child gets 0. + + If the clone call specifies a NULL rsp for the new thread, then + it actually gets a copy of the parent's rsp. + */ + /* We inherit our parent's guest state. */ + ctst->arch.vex = ptst->arch.vex; + ctst->arch.vex_shadow1 = ptst->arch.vex_shadow1; + ctst->arch.vex_shadow2 = ptst->arch.vex_shadow2; + + /* Make sys_clone appear to have returned Success(0) in the + child. */ + ctst->arch.vex.guest_EAX = 0; + ctst->arch.vex.guest_EDX = 0; + LibVEX_GuestX86_put_eflag_c(0, &ctst->arch.vex); + + ctst->os_state.parent = tid; + + /* inherit signal mask */ + ctst->sig_mask = ptst->sig_mask; + ctst->tmp_sig_mask = ptst->sig_mask; + + /* Linux has to guess, we don't */ + ctst->client_stack_highest_byte = (Addr)tp.stack_base + tp.stack_size; + ctst->client_stack_szB = tp.stack_size; + ctst->os_state.stk_id = VG_(register_stack)((Addr)tp.stack_base, (Addr)tp.stack_base + tp.stack_size); + + /* Assume the clone will succeed, and tell any tool that wants to + know that this thread has come into existence. If the clone + fails, we'll send out a ll_exit notification for it at the out: + label below, to clean up. */ + VG_TRACK ( pre_thread_ll_create, tid, ctid ); + + if (debug) + VG_(printf)("clone child has SETTLS: tls at %#lx\n", (Addr)tp.tls_base); + sys_set_thread_area( ctid, &idx, tp.tls_base ); + ctst->arch.vex.guest_GS = (idx << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */ + tp.tls_base = 0; /* Don't have the kernel do it too */ + + /* start the thread with everything blocked */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask); + + /* Set the client state for scheduler to run libthr's trampoline */ + ctst->arch.vex.guest_ESP = (Addr)tp.stack_base + tp.stack_size - 8; + ctst->arch.vex.guest_EIP = (Addr)tp.start_func; + *(UWord *)(ctst->arch.vex.guest_ESP + 4) = (UWord)tp.arg; /* Client arg */ + *(UWord *)(ctst->arch.vex.guest_ESP + 0) = 0; /* fake return addr */ + + /* Set up valgrind's trampoline on its own stack */ + stk = ML_(allocstack)(ctid); + tp.stack_base = (void *)ctst->os_state.valgrind_stack_base; + tp.stack_size = (Addr)stk - (Addr)tp.stack_base; + /* This is for thr_new() to run valgrind's trampoline */ + tp.start_func = (void *)ML_(start_thread_NORETURN); + tp.arg = &VG_(threads)[ctid]; + + /* Create the new thread */ + res = VG_(do_syscall2)(__NR_thr_new, (UWord)&tp, sizeof(tp)); + + VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL); + + if (sr_isError(res)) { + /* clone failed */ + VG_(cleanup_thread)(&ctst->arch); + ctst->status = VgTs_Empty; + /* oops. Better tell the tool the thread exited in a hurry :-) */ + VG_TRACK( pre_thread_ll_exit, ctid ); + } else { + + POST_MEM_WRITE((Addr)tp.parent_tid, sizeof(long)); + POST_MEM_WRITE((Addr)tp.child_tid, sizeof(long)); + POST_MEM_WRITE((Addr)ctst->arch.vex.guest_ESP, 8); + + /* Thread creation was successful; let the child have the chance + to run */ + *flags |= SfYieldAfter; + } + + /* "Complete" the syscall so that the wrapper doesn't call the kernel again. */ + SET_STATUS_from_SysRes(res); +} + +// SYS_pread 475 +// ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset); +PRE(sys_pread) +{ + *flags |= SfMayBlock; + PRINT("sys_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4, ARG5); + PRE_REG_READ5(ssize_t, "pread", + unsigned int, fd, char *, buf, vki_size_t, count, + unsigned int, off_low, unsigned int, off_high); + + if (!ML_(fd_allowed)(ARG1, "pread", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_WRITE( "pread(buf)", ARG2, ARG3 ); +} + +POST(sys_pread) +{ + vg_assert(SUCCESS); + POST_MEM_WRITE( ARG2, RES ); +} + +// SYS_pwrite 476 +// ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset); +PRE(sys_pwrite) +{ + Bool ok; + *flags |= SfMayBlock; + PRINT("sys_pwrite ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %llu )", ARG1, ARG2, ARG3, MERGE64(ARG4, ARG5)); + PRE_REG_READ5(ssize_t, "pwrite", + unsigned int, fd, const char *, buf, vki_size_t, count, + vki_uint32_t, MERGE64_FIRST(offset), + vki_uint32_t, MERGE64_SECOND(offset)); + /* check to see if it is allowed. If not, try for an exemption from + --sim-hints=enable-outer (used for self hosting). */ + ok = ML_(fd_allowed)(ARG1, "pwrite", tid, False); + if (!ok && ARG1 == 2/*stderr*/ + && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints))) + ok = True; + if (!ok) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_READ( "pwrite(buf)", ARG2, ARG3 ); +} + +// SYS_mmap 477 +// void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset); +PRE(sys_mmap) +{ + SysRes r; + + PRINT("sys_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %llu )", + ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, MERGE64(ARG6, ARG7) ); + PRE_REG_READ7(void *, "mmap", + void *, addr, size_t, len, int, prot, int, flags, int, fd, + vki_uint32_t, MERGE64_FIRST(offset), + vki_uint32_t, MERGE64_SECOND(offset)); + + r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, MERGE64(ARG6,ARG7) ); + SET_STATUS_from_SysRes(r); +} + +// SYS_lseek 478 +// off_t lseek(int fildes, off_t offset, int whence); +PRE(sys_lseek) +{ + PRINT("sys_lseek ( %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "d )", SARG1,MERGE64(ARG2,ARG3),SARG4); + PRE_REG_READ4(long, "lseek", + unsigned int, fd, + vki_uint32_t, MERGE64_FIRST(offset), + vki_uint32_t, MERGE64_SECOND(offset), + unsigned int, whence); +} + +// SYS_truncate 479 +// int truncate(const char *path, off_t length); +PRE(sys_truncate) +{ + *flags |= SfMayBlock; + PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %llu )", ARG1,(char *)ARG1,MERGE64(ARG2,ARG3)); + PRE_REG_READ3(long, "truncate", + const char *, path, + vki_uint32_t, MERGE64_FIRST(length), + vki_uint32_t, MERGE64_SECOND(length)); + PRE_MEM_RASCIIZ( "truncate(path)", ARG1 ); +} + +// SYS_ftruncate 480 +// int ftruncate(int fd, off_t length); +PRE(sys_ftruncate) +{ + *flags |= SfMayBlock; + PRINT("sys_ftruncate ( %" FMT_REGWORD "d, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", SARG1,ARG2,ARG3); + PRE_REG_READ3(int, "ftruncate", int, fd, + vki_uint32_t, MERGE64_FIRST(length), + vki_uint32_t, MERGE64_SECOND(length)); +} + +// SYS_cpuset_setid 485 +// int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid); +PRE(sys_cpuset_setid) +{ + PRINT("sys_cpuset_setid ( %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x )", + SARG1, MERGE64(ARG2,ARG3), ARG4); + PRE_REG_READ4(int, "cpuset_setid", vki_cpuwhich_t, which, + vki_uint32_t, MERGE64_FIRST(id), + vki_uint32_t, MERGE64_SECOND(id), + vki_cpusetid_t,setid); +} + +// SYS_cpuset_getid 486 +// int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id, +// cpusetid_t *setid); +PRE(sys_cpuset_getid) +{ + PRINT("sys_cpuset_getid ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x )", + SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5); + PRE_REG_READ5(int, "cpuset_getid", vki_cpulevel_t, level, + vki_cpuwhich_t, which, + vki_uint32_t, MERGE64_FIRST(id), + vki_uint32_t, MERGE64_SECOND(id), + vki_cpusetid_t *,setid); + PRE_MEM_WRITE("cpuset_getid(setid)", ARG4, sizeof(vki_cpusetid_t)); +} + +POST(sys_cpuset_getid) +{ + POST_MEM_WRITE(ARG5, sizeof(vki_cpusetid_t)); +} + +// SYS_cpuset_getaffinity 487 +// int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id, +// size_t setsize, cpuset_t *mask); +PRE(sys_cpuset_getaffinity) +{ + PRINT("sys_cpuset_getaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %lld, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", + ARG1, ARG2, MERGE64(ARG3, ARG4), ARG5, ARG6); + PRE_REG_READ6(int, "cpuset_getaffinity", + vki_cpulevel_t, level, vki_cpuwhich_t, which, + vki_uint32_t, MERGE64_FIRST(id), + vki_uint32_t, MERGE64_SECOND(id), + size_t, setsize, void *, mask); + PRE_MEM_WRITE("cpuset_getaffinity", ARG6, ARG5); +} + +POST(sys_cpuset_getaffinity) +{ + vg_assert(SUCCESS); + if (RES == 0) + POST_MEM_WRITE( ARG6, ARG5 ); +} + +// SYS_cpuset_setaffinity 488 +// int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id, +// size_t setsize, const cpuset_t *mask); +PRE(sys_cpuset_setaffinity) +{ + + PRINT("sys_cpuset_setaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", + ARG1, ARG2, MERGE64(ARG3, ARG4), ARG5, ARG6); + PRE_REG_READ6(int, "cpuset_setaffinity", + vki_cpulevel_t, level, vki_cpuwhich_t, which, + vki_uint32_t, MERGE64_FIRST(id), + vki_uint32_t, MERGE64_SECOND(id), + size_t, setsize, void *, mask); + PRE_MEM_READ("cpuset_setaffinity", ARG6, ARG5); +} + +// SYS_posix_fallocate 530 +// int posix_fallocate(int fd, off_t offset, off_t len); +PRE(sys_posix_fallocate) +{ + PRINT("sys_posix_fallocate ( %" FMT_REGWORD "d, %llu, %llu )", + SARG1, MERGE64(ARG2,ARG3), MERGE64(ARG4, ARG5)); + PRE_REG_READ5(long, "posix_fallocate", + int, fd, vki_uint32_t, MERGE64_FIRST(offset), + vki_uint32_t, MERGE64_SECOND(offset), + vki_uint32_t, MERGE64_FIRST(len), + vki_uint32_t, MERGE64_SECOND(len)); +} + +// SYS_posix_fadvise 531 +// int posix_fadvise(int fd, off_t offset, off_t len, int advice); +PRE(sys_posix_fadvise) +{ + PRINT("sys_posix_fadvise ( %" FMT_REGWORD "d, %llu, %llu, %" FMT_REGWORD "d )", + SARG1, MERGE64(ARG2,ARG3), MERGE64(ARG4,ARG5), SARG6); + PRE_REG_READ6(long, "posix_fadvise", + int, fd, vki_uint32_t, MERGE64_FIRST(offset), + vki_uint32_t, MERGE64_SECOND(offset), + vki_uint32_t, MERGE64_FIRST(len), + vki_uint32_t, MERGE64_SECOND(len), + int, advice); +} + +// SYS_wait6 532 +// pid_t wait6(idtype_t idtype, id_t id, int *status, int options, +// struct __wrusage *wrusage, siginfo_t *infop); +PRE(sys_wait6) +{ + PRINT("sys_wait6 ( %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + SARG1, MERGE64(ARG2, ARG3), ARG4, SARG5, ARG6, ARG7); + PRE_REG_READ7(pid_t, "wait6", vki_idtype_t, idtype, + vki_uint32_t, MERGE64_FIRST(id), + vki_uint32_t, MERGE64_SECOND(id), + int *, status, int, options, + struct vki___wrusage *, wrusage, vki_siginfo_t *,infop); + PRE_MEM_WRITE("wait6(status)", ARG4, sizeof(int)); + if (ARG6) { + PRE_MEM_WRITE("wait6(wrusage)", ARG6, sizeof(struct vki___wrusage)); + } + if (ARG7) { + PRE_MEM_WRITE("wait6(infop)", ARG7, sizeof(vki_siginfo_t)); + } +} + +POST(sys_wait6) +{ + POST_MEM_WRITE(ARG4, sizeof(int)); + if (ARG6) { + POST_MEM_WRITE(ARG6, sizeof(struct vki___wrusage)); + } + + if (ARG7) { + POST_MEM_WRITE(ARG7, sizeof(vki_siginfo_t)); + } +} + +// the man page is inconsistent for the last argument +// See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=247386 +// will stick to 'arg' for simplicity + +// SYS_procctl 544 +// int procctl(idtype_t idtype, id_t id, int cmd, void *arg); +PRE(sys_procctl) +{ + PRINT("sys_procctl ( %" FMT_REGWORD "d, %llu, %" FMT_REGWORD"d, %#" FMT_REGWORD "x )", + SARG1, MERGE64(ARG2, ARG3), SARG4, ARG5); + PRE_REG_READ5(int, "procctl", vki_idtype_t, idtype, + vki_uint32_t, MERGE64_FIRST(id), + vki_uint32_t, MERGE64_SECOND(id), + int, cmd, void *, arg); + switch (ARG4) { + case PROC_ASLR_CTL: + case PROC_SPROTECT: + case PROC_TRACE_CTL: + case PROC_TRAPCAP_CTL: + case PROC_PDEATHSIG_CTL: + case PROC_STACKGAP_CTL: + PRE_MEM_READ("procctl(arg)", ARG5, sizeof(int)); + break; + case PROC_REAP_STATUS: + PRE_MEM_READ("procctl(arg)", ARG5, sizeof(struct vki_procctl_reaper_status)); + break; + case PROC_REAP_GETPIDS: + PRE_MEM_READ("procctl(arg)", ARG5, sizeof(struct vki_procctl_reaper_pids)); + break; + case PROC_REAP_KILL: + /* The first three fields are reads + * int rk_sig; + * u_int rk_flags; + * pid_t rk_subtree; + * + * The last two fields are writes + * u_int rk_killed; + * pid_t rk_fpid; + * + * There is also a pad field + */ + PRE_MEM_READ("procctl(arg)", ARG5, sizeof(int) + sizeof(u_int) + sizeof(vki_pid_t)); + PRE_MEM_WRITE("procctl(arg)", ARG5+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t)); + break; + case PROC_ASLR_STATUS: + case PROC_PDEATHSIG_STATUS: + case PROC_STACKGAP_STATUS: + case PROC_TRAPCAP_STATUS: + case PROC_TRACE_STATUS: + PRE_MEM_WRITE("procctl(arg)", ARG5, sizeof(int)); + case PROC_REAP_ACQUIRE: + case PROC_REAP_RELEASE: + default: + break; + } +} + +POST(sys_procctl) +{ + switch (ARG4) { + case PROC_REAP_KILL: + POST_MEM_WRITE(ARG5+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t)); + break; + case PROC_ASLR_STATUS: + case PROC_PDEATHSIG_STATUS: + case PROC_STACKGAP_STATUS: + case PROC_TRAPCAP_STATUS: + case PROC_TRACE_STATUS: + POST_MEM_WRITE(ARG5, sizeof(int)); + default: + break; + } +} + +#if (FREEBSD_VERS >= FREEBSD_12) + +// SYS_cpuset_getdomain 561 +// int cpuset_getdomain(cpulevel_t level, cpuwhich_t which, id_t id, +// size_t setsize, domainset_t *mask, int *policy); +PRE(sys_cpuset_getdomain) +{ + PRINT("sys_cpuset_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5, ARG6, ARG7); + PRE_REG_READ7(int, "cpuset_getdomain", + cpulevel_t, level, cpuwhich_t, which, + vki_uint32_t, MERGE64_FIRST(id), + vki_uint32_t, MERGE64_SECOND(id), + size_t, setsize, vki_domainset_t *, mask, int *, policy); + // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)" + PRE_MEM_WRITE( "cpuset_getdomain(mask)", ARG6, ARG5 ); + PRE_MEM_WRITE( "cpuset_getdomain(policy)", ARG7, sizeof(int) ); +} + +POST(sys_cpuset_getdomain) +{ + POST_MEM_WRITE(ARG5, ARG4 ); + POST_MEM_WRITE(ARG6, sizeof(int) ); +} + +// SYS_cpuset_setdomain 562 +// int cuset_setdomain(cpulevel_t level, cpuwhich_t which, id_t id, +// size_t setsize, const domainset_t *mask, int policy); +PRE(sys_cpuset_setdomain) +{ + PRINT("sys_cpuget_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )", + SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5, ARG6, SARG7); + PRE_REG_READ7(int, "cpuset_getdomain", + cpulevel_t, level, cpuwhich_t, which, + vki_uint32_t, MERGE64_FIRST(id), + vki_uint32_t, MERGE64_SECOND(id), + size_t, setsize, vki_domainset_t *, mask, int, policy); + // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)" + PRE_MEM_READ( "cpuset_getdomain(mask)", ARG6, ARG5 ); +} + +#endif + +PRE(sys_fake_sigreturn) +{ + /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for + an explanation of what follows. */ + + ThreadState* tst; + struct vki_ucontext *uc; + PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1); + PRE_REG_READ1(long, "sigreturn", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); + + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(tid >= 1 && tid < VG_N_THREADS); + vg_assert(VG_(is_running_thread)(tid)); + + /* Adjust esp to point to start of frame; skip back up over handler + ret addr */ + tst = VG_(get_ThreadState)(tid); + tst->arch.vex.guest_ESP -= sizeof(Addr); /* QQQ should be redundant */ + + uc = (struct vki_ucontext *)ARG1; + if (uc == NULL || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + + /* This is only so that the EIP is (might be) useful to report if + something goes wrong in the sigreturn */ + ML_(fixup_guest_state_to_restart_syscall)(&tst->arch); + + /* Restore register state from frame and remove it */ + VG_(sigframe_destroy)(tid); + + /* For unclear reasons, it appears we need the syscall to return + without changing %EAX. Since %EAX is the return value, and can + denote either success or failure, we must set up so that the + driver logic copies it back unchanged. Also, note %EAX is of + the guest registers written by VG_(sigframe_destroy). */ + int eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex); + SET_STATUS_from_SysRes( VG_(mk_SysRes_x86_freebsd)( tst->arch.vex.guest_EAX, + tst->arch.vex.guest_EDX, (eflags & 1) != 0 ? True : False) ); + + /* + * Signal handler might have changed the signal mask. Respect that. + */ + tst->sig_mask = uc->uc_sigmask; + tst->tmp_sig_mask = uc->uc_sigmask; + + /* Tell the driver not to update the guest state with the "result", + and set a bogus result to keep it happy. */ + *flags |= SfNoWriteResult; + SET_STATUS_Success(0); + + /* Check to see if any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + +#undef PRE +#undef POST + + +#endif /* defined(VGP_x86_freebsd) */ + + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/