1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Handle system calls.                          syswrap-main.c ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Copyright (C) 2000-2013 Julian Seward
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jseward@acm.org
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_guest_offsets.h"
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_trc_values.h"
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_basics.h"
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_aspacemgr.h"
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vki.h"
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_vkiscnums.h"
37b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#include "pub_core_libcsetjmp.h"    // to keep _threadstate.h happy
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_threadstate.h"
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcbase.h"
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcassert.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcprint.h"
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcproc.h"      // For VG_(getpid)()
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_libcsignal.h"
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_scheduler.h"     // For VG_({acquire,release}_BigLock),
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    //   and VG_(vg_yield)
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_stacktrace.h"    // For VG_(get_and_pp_StackTrace)()
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_tooliface.h"
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_options.h"
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_signals.h"       // For VG_SIGVGKILL, VG_(poll_signals)
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_syscall.h"
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_machine.h"
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_core_syswrap.h"
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_types_n_macros.h"
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_syswrap-main.h"
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_darwin)
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "priv_syswrap-darwin.h"
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Useful info which needs to be recorded somewhere:
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Use of registers in syscalls is:
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
64b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov          NUM   ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7 ARG8 RESULT
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   LINUX:
66b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   x86    eax   ebx  ecx  edx  esi  edi  ebp  n/a  n/a  eax       (== NUM)
67b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   amd64  rax   rdi  rsi  rdx  r10  r8   r9   n/a  n/a  rax       (== NUM)
68b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   ppc32  r0    r3   r4   r5   r6   r7   r8   n/a  n/a  r3+CR0.SO (== ARG1)
69b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   ppc64  r0    r3   r4   r5   r6   r7   r8   n/a  n/a  r3+CR0.SO (== ARG1)
70b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   arm    r7    r0   r1   r2   r3   r4   r5   n/a  n/a  r0        (== ARG1)
71436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   mips32 v0    a0   a1   a2   a3 stack stack n/a  n/a  v0        (== NUM)
72436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   mips64 v0    a0   a1   a2   a3   a4   a5   a6   a7   v0        (== NUM)
73436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   arm64  x8    x0   x1   x2   x3   x4   x5   n/a  n/a  x0 ??     (== ARG1??)
74b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
75b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   On s390x the svc instruction is used for system calls. The system call
76b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   number is encoded in the instruction (8 bit immediate field). Since Linux
77b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   2.6 it is also allowed to use svc 0 with the system call number in r1.
78b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   This was introduced for system calls >255, but works for all. It is
79b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   also possible to see the svc 0 together with an EXecute instruction, that
80b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fills in the immediate field.
81b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   s390x r1/SVC r2   r3   r4   r5   r6   r7   n/a  n/a  r2        (== ARG1)
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DARWIN:
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x86    eax +4   +8   +12  +16  +20  +24  +28  +32  edx:eax, eflags.c
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amd64  rax rdi  rsi  rdx  rcx  r8   r9   +8   +16  rdx:rax, rflags.c
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   For x86-darwin, "+N" denotes "in memory at N(%esp)"; ditto
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amd64-darwin.  Apparently 0(%esp) is some kind of return address
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (perhaps for syscalls done with "sysenter"?)  I don't think it is
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   relevant for syscalls done with "int $0x80/1/2".
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the top level of the system-call handler module.  All
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   system calls are channelled through here, doing two things:
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * notify the tool of the events (mem/reg reads, writes) happening
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * perform the syscall, usually by passing it along to the kernel
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     unmodified.
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   A magical piece of assembly code, do_syscall_for_client_WRK, in
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscall-$PLATFORM.S does the tricky bit of passing a syscall to the
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   kernel, whilst having the simulator retain control.
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The main function is VG_(client_syscall).  The simulation calls it
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   whenever a client thread wants to do a syscall.  The following is a
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sketch of what it does.
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * Ensures the root thread's stack is suitably mapped.  Tedious and
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     arcane.  See big big comment in VG_(client_syscall).
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * First, it rounds up the syscall number and args (which is a
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     platform dependent activity) and puts them in a struct ("args")
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     and also a copy in "orig_args".
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     The pre/post wrappers refer to these structs and so no longer
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     need magic macros to access any specific registers.  This struct
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     is stored in thread-specific storage.
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * The pre-wrapper is called, passing it a pointer to struct
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     "args".
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * The pre-wrapper examines the args and pokes the tool
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     appropriately.  It may modify the args; this is why "orig_args"
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     is also stored.
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     The pre-wrapper may choose to 'do' the syscall itself, and
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     concludes one of three outcomes:
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       Success(N)    -- syscall is already complete, with success;
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        result is N
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       Fail(N)       -- syscall is already complete, with failure;
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        error code is N
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       HandToKernel  -- (the usual case): this needs to be given to
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        the kernel to be done, using the values in
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        the possibly-modified "args" struct.
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     In addition, the pre-wrapper may set some flags:
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       MayBlock   -- only applicable when outcome==HandToKernel
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       PostOnFail -- only applicable when outcome==HandToKernel or Fail
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * If the pre-outcome is HandToKernel, the syscall is duly handed
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     off to the kernel (perhaps involving some thread switchery, but
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     that's not important).  This reduces the possible set of outcomes
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     to either Success(N) or Fail(N).
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * The outcome (Success(N) or Fail(N)) is written back to the guest
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     register(s).  This is platform specific:
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     x86:    Success(N) ==>  eax = N
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Fail(N)    ==>  eax = -N
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     ditto amd64
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     ppc32:  Success(N) ==>  r3 = N, CR0.SO = 0
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Fail(N) ==>     r3 = N, CR0.SO = 1
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Darwin:
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     x86:    Success(N) ==>  edx:eax = N, cc = 0
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Fail(N)    ==>  edx:eax = N, cc = 1
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
171b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     s390x:  Success(N) ==>  r2 = N
172b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             Fail(N)    ==>  r2 = -N
173b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * The post wrapper is called if:
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     - it exists, and
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     - outcome==Success or (outcome==Fail and PostOnFail is set)
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     The post wrapper is passed the adulterated syscall args (struct
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     "args"), and the syscall outcome (viz, Success(N) or Fail(N)).
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   There are several other complications, primarily to do with
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscalls getting interrupted, explained in comments in the code.
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* CAVEATS for writing wrappers.  It is important to follow these!
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The macros defined in priv_types_n_macros.h are designed to help
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   decouple the wrapper logic from the actual representation of
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscall args/results, since these wrappers are designed to work on
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   multiple platforms.
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Sometimes a PRE wrapper will complete the syscall itself, without
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   handing it to the kernel.  It will use one of SET_STATUS_Success,
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SET_STATUS_Failure or SET_STATUS_from_SysRes to set the return
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value.  It is critical to appreciate that use of the macro does not
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   immediately cause the underlying guest state to be updated -- that
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is done by the driver logic in this file, when the wrapper returns.
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   As a result, PRE wrappers of the following form will malfunction:
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRE(fooble)
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ... do stuff ...
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SET_STATUS_Somehow(...)
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // do something that assumes guest state is up to date
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   In particular, direct or indirect calls to VG_(poll_signals) after
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setting STATUS can cause the guest state to be read (in order to
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   build signal frames).  Do not do this.  If you want a signal poll
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   after the syscall goes through, do "*flags |= SfPollAfter" and the
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   driver logic will do it for you.
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   -----------
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Another critical requirement following introduction of new address
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space manager (JRS, 20050923):
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   In a situation where the mappedness of memory has changed, aspacem
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   should be notified BEFORE the tool.  Hence the following is
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   correct:
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool d = VG_(am_notify_munmap)(s->start, s->end+1 - s->start);
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( die_mem_munmap, s->start, s->end+1 - s->start );
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d)
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(discard_translations)(s->start, s->end+1 - s->start);
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   whilst this is wrong:
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( die_mem_munmap, s->start, s->end+1 - s->start );
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool d = VG_(am_notify_munmap)(s->start, s->end+1 - s->start);
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d)
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(discard_translations)(s->start, s->end+1 - s->start);
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The reason is that the tool may itself ask aspacem for more shadow
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memory as a result of the VG_TRACK call.  In such a situation it is
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   critical that aspacem's segment array is up to date -- hence the
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   need to notify aspacem first.
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   -----------
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Also .. take care to call VG_(discard_translations) whenever
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memory with execute permissions is unmapped.
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Do potentially blocking syscall for the client, and mess with
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   signal masks at the same time.
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Perform a syscall on behalf of a client thread, using a specific
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   signal mask.  On completion, the signal mask is set to restore_mask
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (which presumably blocks almost everything).  If a signal happens
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   during the syscall, the handler should call
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(fixup_guest_state_after_syscall_interrupted) to adjust the
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread's context to do the right thing.
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The _WRK function is handwritten assembly, implemented per-platform
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in coregrind/m_syswrap/syscall-$PLAT.S.  It has some very magic
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   properties.  See comments at the top of
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(fixup_guest_state_after_syscall_interrupted) below for details.
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This function (these functions) are required to return zero in case
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of success (even if the syscall itself failed), and nonzero if the
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sigprocmask-swizzling calls failed.  We don't actually care about
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the failure values from sigprocmask, although most of the assembly
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   implementations do attempt to return that, using the convention
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0 for success, or 0x8000 | error-code for failure.
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux)
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownextern
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUWord ML_(do_syscall_for_client_WRK)( Word syscallno,
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      void* guest_state,
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      const vki_sigset_t *syscall_mask,
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      const vki_sigset_t *restore_mask,
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      Word sigsetSzB );
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGO_darwin)
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownextern
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUWord ML_(do_syscall_for_client_unix_WRK)( Word syscallno,
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           void* guest_state,
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *syscall_mask,
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *restore_mask,
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Word sigsetSzB ); /* unused */
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownextern
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUWord ML_(do_syscall_for_client_mach_WRK)( Word syscallno,
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           void* guest_state,
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *syscall_mask,
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *restore_mask,
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Word sigsetSzB ); /* unused */
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownextern
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUWord ML_(do_syscall_for_client_mdep_WRK)( Word syscallno,
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           void* guest_state,
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *syscall_mask,
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *restore_mask,
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Word sigsetSzB ); /* unused */
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "Unknown OS"
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid do_syscall_for_client ( Int syscallno,
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             ThreadState* tst,
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             const vki_sigset_t* syscall_mask )
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vki_sigset_t saved;
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord err;
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   err = ML_(do_syscall_for_client_WRK)(
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            syscallno, &tst->arch.vex,
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            syscall_mask, &saved, sizeof(vki_sigset_t)
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (VG_DARWIN_SYSNO_CLASS(syscallno)) {
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_UNIX:
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         err = ML_(do_syscall_for_client_unix_WRK)(
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  VG_DARWIN_SYSNO_FOR_KERNEL(syscallno), &tst->arch.vex,
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  syscall_mask, &saved, 0/*unused:sigsetSzB*/
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MACH:
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         err = ML_(do_syscall_for_client_mach_WRK)(
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  VG_DARWIN_SYSNO_FOR_KERNEL(syscallno), &tst->arch.vex,
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  syscall_mask, &saved, 0/*unused:sigsetSzB*/
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MDEP:
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         err = ML_(do_syscall_for_client_mdep_WRK)(
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  VG_DARWIN_SYSNO_FOR_KERNEL(syscallno), &tst->arch.vex,
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  syscall_mask, &saved, 0/*unused:sigsetSzB*/
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert2(
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      err == 0,
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "ML_(do_syscall_for_client_WRK): sigprocmask error %d",
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Int)(err & 0xFFF)
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Impedance matchers and misc helpers
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool eq_SyscallArgs ( SyscallArgs* a1, SyscallArgs* a2 )
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return a1->sysno == a2->sysno
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg1 == a2->arg1
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg2 == a2->arg2
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg3 == a2->arg3
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg4 == a2->arg4
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg5 == a2->arg5
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg6 == a2->arg6
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg7 == a2->arg7
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg8 == a2->arg8;
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool eq_SyscallStatus ( SyscallStatus* s1, SyscallStatus* s2 )
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* was: return s1->what == s2->what && sr_EQ( s1->sres, s2->sres ); */
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (s1->what == s2->what && sr_EQ( s1->sres, s2->sres ))
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_darwin)
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Darwin-specific debugging guff */
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(s1->what == s2->what);
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("eq_SyscallStatus:\n");
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("  {%lu %lu %u}\n", s1->sres._wLO, s1->sres._wHI, s1->sres._mode);
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("  {%lu %lu %u}\n", s2->sres._wLO, s2->sres._wHI, s2->sres._mode);
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Convert between SysRes and SyscallStatus, to the extent possible. */
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSyscallStatus convert_SysRes_to_SyscallStatus ( SysRes res )
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallStatus status;
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   status.what = SsComplete;
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   status.sres = res;
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return status;
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Impedance matchers.  These convert syscall arg or result data from
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the platform-specific in-guest-state format to the canonical
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   formats, and back. */
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid getSyscallArgsFromGuestState ( /*OUT*/SyscallArgs*       canonical,
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    /*IN*/ VexGuestArchState* gst_vanilla,
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    /*IN*/ UInt trc )
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_x86_linux)
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_EAX;
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg1  = gst->guest_EBX;
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg2  = gst->guest_ECX;
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg3  = gst->guest_EDX;
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg4  = gst->guest_ESI;
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg5  = gst->guest_EDI;
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg6  = gst->guest_EBP;
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg7  = 0;
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg8  = 0;
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_linux)
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_RAX;
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg1  = gst->guest_RDI;
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg2  = gst->guest_RSI;
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg3  = gst->guest_RDX;
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg4  = gst->guest_R10;
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg5  = gst->guest_R8;
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg6  = gst->guest_R9;
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg7  = 0;
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg8  = 0;
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc32_linux)
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_GPR0;
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg1  = gst->guest_GPR3;
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg2  = gst->guest_GPR4;
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg3  = gst->guest_GPR5;
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg4  = gst->guest_GPR6;
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg5  = gst->guest_GPR7;
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg6  = gst->guest_GPR8;
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg7  = 0;
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg8  = 0;
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc64_linux)
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_GPR0;
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg1  = gst->guest_GPR3;
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg2  = gst->guest_GPR4;
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg3  = gst->guest_GPR5;
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg4  = gst->guest_GPR6;
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg5  = gst->guest_GPR7;
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg6  = gst->guest_GPR8;
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg7  = 0;
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg8  = 0;
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_arm_linux)
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_R7;
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg1  = gst->guest_R0;
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg2  = gst->guest_R1;
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg3  = gst->guest_R2;
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg4  = gst->guest_R3;
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg5  = gst->guest_R4;
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg6  = gst->guest_R5;
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg7  = 0;
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg8  = 0;
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
468436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#elif defined(VGP_arm64_linux)
469436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexGuestARM64State* gst = (VexGuestARM64State*)gst_vanilla;
470436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->sysno = gst->guest_X8;
471436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg1  = gst->guest_X0;
472436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg2  = gst->guest_X1;
473436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg3  = gst->guest_X2;
474436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg4  = gst->guest_X3;
475436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg5  = gst->guest_X4;
476436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg6  = gst->guest_X5;
477436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg7  = 0;
478436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg8  = 0;
479436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
480663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#elif defined(VGP_mips32_linux)
481663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VexGuestMIPS32State* gst = (VexGuestMIPS32State*)gst_vanilla;
482663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   canonical->sysno = gst->guest_r2;    // v0
483436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (canonical->sysno == __NR_exit) {
484436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      canonical->arg1 = gst->guest_r4;    // a0
485436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      canonical->arg2 = 0;
486436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      canonical->arg3 = 0;
487436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      canonical->arg4 = 0;
488436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      canonical->arg5 = 0;
489436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      canonical->arg6 = 0;
490436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      canonical->arg8 = 0;
491436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else if (canonical->sysno != __NR_syscall) {
492663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg1  = gst->guest_r4;    // a0
493663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg2  = gst->guest_r5;    // a1
494663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg3  = gst->guest_r6;    // a2
495663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg4  = gst->guest_r7;    // a3
496663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg5  = *((UInt*) (gst->guest_r29 + 16));    // 16(guest_SP/sp)
497663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg6  = *((UInt*) (gst->guest_r29 + 20));    // 20(sp)
498663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg8 = 0;
499663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   } else {
500663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      // Fixme hack handle syscall()
501663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->sysno = gst->guest_r4;    // a0
502663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg1  = gst->guest_r5;    // a1
503663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg2  = gst->guest_r6;    // a2
504663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg3  = gst->guest_r7;    // a3
505663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg4  = *((UInt*) (gst->guest_r29 + 16));    // 16(guest_SP/sp)
506663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg5  = *((UInt*) (gst->guest_r29 + 20));    // 20(guest_SP/sp)
507663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg6  = *((UInt*) (gst->guest_r29 + 24));    // 24(guest_SP/sp)
508663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg8 = __NR_syscall;
509663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
510663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
511436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#elif defined(VGP_mips64_linux)
512436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexGuestMIPS64State* gst = (VexGuestMIPS64State*)gst_vanilla;
513436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->sysno = gst->guest_r2;    // v0
514436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg1  = gst->guest_r4;    // a0
515436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg2  = gst->guest_r5;    // a1
516436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg3  = gst->guest_r6;    // a2
517436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg4  = gst->guest_r7;    // a3
518436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg5  = gst->guest_r8;    // a4
519436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->arg6  = gst->guest_r9;    // a5
520436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_x86_darwin)
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord *stack = (UWord *)gst->guest_ESP;
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme hope syscalls aren't called with really shallow stacks...
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_EAX;
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (canonical->sysno != 0) {
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // stack[0] is return address
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg1  = stack[1];
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg2  = stack[2];
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg3  = stack[3];
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg4  = stack[4];
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg5  = stack[5];
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg6  = stack[6];
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg7  = stack[7];
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg8  = stack[8];
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme hack handle syscall()
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme what about __syscall() ?
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // stack[0] is return address
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // DDD: the tool can't see that the params have been shifted!  Can
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //      lead to incorrect checking, I think, because the PRRAn/PSARn
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //      macros will mention the pre-shifted args.
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->sysno = stack[1];
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(canonical->sysno != 0);
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg1  = stack[2];
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg2  = stack[3];
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg3  = stack[4];
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg4  = stack[5];
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg5  = stack[6];
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg6  = stack[7];
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg7  = stack[8];
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg8  = stack[9];
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      PRINT("SYSCALL[%d,?](%s) syscall(%s, ...); please stand by...\n",
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(getpid)(), /*tid,*/
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_SYSNUM_STRING(0), VG_SYSNUM_STRING(canonical->sysno));
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Here we determine what kind of syscall it was by looking at the
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // interrupt kind, and then encode the syscall number using the 64-bit
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // encoding for Valgrind's internal use.
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // DDD: Would it be better to stash the JMP kind into the Darwin
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // thread state rather than passing in the trc?
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (trc) {
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VEX_TRC_JMP_SYS_INT128:
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // int $0x80 = Unix, 64-bit result
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(canonical->sysno >= 0);
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(canonical->sysno);
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VEX_TRC_JMP_SYS_SYSENTER:
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // syscall = Unix, 32-bit result
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // OR        Mach, 32-bit result
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (canonical->sysno >= 0) {
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // GrP fixme hack:  0xffff == I386_SYSCALL_NUMBER_MASK
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(canonical->sysno
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                             & 0xffff);
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MACH(-canonical->sysno);
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VEX_TRC_JMP_SYS_INT129:
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // int $0x81 = Mach, 32-bit result
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(canonical->sysno < 0);
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MACH(-canonical->sysno);
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VEX_TRC_JMP_SYS_INT130:
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // int $0x82 = mdep, 32-bit result
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(canonical->sysno >= 0);
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(canonical->sysno);
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0);
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_darwin)
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord *stack = (UWord *)gst->guest_RSP;
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(trc == VEX_TRC_JMP_SYS_SYSCALL);
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme hope syscalls aren't called with really shallow stacks...
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_RAX;
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (canonical->sysno != __NR_syscall) {
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // stack[0] is return address
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg1  = gst->guest_RDI;
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg2  = gst->guest_RSI;
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg3  = gst->guest_RDX;
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg4  = gst->guest_R10;  // not rcx with syscall insn
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg5  = gst->guest_R8;
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg6  = gst->guest_R9;
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg7  = stack[1];
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg8  = stack[2];
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme hack handle syscall()
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme what about __syscall() ?
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // stack[0] is return address
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // DDD: the tool can't see that the params have been shifted!  Can
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //      lead to incorrect checking, I think, because the PRRAn/PSARn
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //      macros will mention the pre-shifted args.
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(gst->guest_RDI);
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(canonical->sysno != __NR_syscall);
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg1  = gst->guest_RSI;
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg2  = gst->guest_RDX;
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg3  = gst->guest_R10;  // not rcx with syscall insn
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg4  = gst->guest_R8;
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg5  = gst->guest_R9;
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg6  = stack[1];
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg7  = stack[2];
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg8  = stack[3];
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      PRINT("SYSCALL[%d,?](%s) syscall(%s, ...); please stand by...\n",
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(getpid)(), /*tid,*/
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_SYSNUM_STRING(0), VG_SYSNUM_STRING(canonical->sysno));
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // no canonical->sysno adjustment needed
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
640b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined(VGP_s390x_linux)
641b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VexGuestS390XState* gst = (VexGuestS390XState*)gst_vanilla;
642b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->sysno = gst->guest_SYSNO;
643b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg1  = gst->guest_r2;
644b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg2  = gst->guest_r3;
645b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg3  = gst->guest_r4;
646b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg4  = gst->guest_r5;
647b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg5  = gst->guest_r6;
648b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg6  = gst->guest_r7;
649b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg7  = 0;
650b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg8  = 0;
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "getSyscallArgsFromGuestState: unknown arch"
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid putSyscallArgsIntoGuestState ( /*IN*/ SyscallArgs*       canonical,
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    /*OUT*/VexGuestArchState* gst_vanilla )
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_x86_linux)
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EAX = canonical->sysno;
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EBX = canonical->arg1;
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_ECX = canonical->arg2;
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EDX = canonical->arg3;
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_ESI = canonical->arg4;
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EDI = canonical->arg5;
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EBP = canonical->arg6;
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_linux)
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RAX = canonical->sysno;
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RDI = canonical->arg1;
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RSI = canonical->arg2;
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RDX = canonical->arg3;
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R10 = canonical->arg4;
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R8  = canonical->arg5;
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R9  = canonical->arg6;
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc32_linux)
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR0 = canonical->sysno;
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR3 = canonical->arg1;
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR4 = canonical->arg2;
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR5 = canonical->arg3;
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR6 = canonical->arg4;
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR7 = canonical->arg5;
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR8 = canonical->arg6;
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc64_linux)
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR0 = canonical->sysno;
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR3 = canonical->arg1;
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR4 = canonical->arg2;
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR5 = canonical->arg3;
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR6 = canonical->arg4;
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR7 = canonical->arg5;
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR8 = canonical->arg6;
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_arm_linux)
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R7 = canonical->sysno;
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R0 = canonical->arg1;
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R1 = canonical->arg2;
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R2 = canonical->arg3;
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R3 = canonical->arg4;
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R4 = canonical->arg5;
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R5 = canonical->arg6;
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
710436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#elif defined(VGP_arm64_linux)
711436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexGuestARM64State* gst = (VexGuestARM64State*)gst_vanilla;
712436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_X8 = canonical->sysno;
713436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_X0 = canonical->arg1;
714436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_X1 = canonical->arg2;
715436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_X2 = canonical->arg3;
716436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_X3 = canonical->arg4;
717436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_X4 = canonical->arg5;
718436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_X5 = canonical->arg6;
719436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_x86_darwin)
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord *stack = (UWord *)gst->guest_ESP;
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EAX = VG_DARWIN_SYSNO_FOR_KERNEL(canonical->sysno);
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme? gst->guest_TEMP_EFLAG_C = 0;
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // stack[0] is return address
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[1] = canonical->arg1;
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[2] = canonical->arg2;
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[3] = canonical->arg3;
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[4] = canonical->arg4;
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[5] = canonical->arg5;
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[6] = canonical->arg6;
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[7] = canonical->arg7;
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[8] = canonical->arg8;
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_darwin)
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord *stack = (UWord *)gst->guest_RSP;
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RAX = VG_DARWIN_SYSNO_FOR_KERNEL(canonical->sysno);
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme? gst->guest_TEMP_EFLAG_C = 0;
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // stack[0] is return address
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RDI = canonical->arg1;
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RSI = canonical->arg2;
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RDX = canonical->arg3;
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RCX = canonical->arg4;
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R8  = canonical->arg5;
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R9  = canonical->arg6;
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[1]       = canonical->arg7;
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[2]       = canonical->arg8;
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
754b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined(VGP_s390x_linux)
755b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VexGuestS390XState* gst = (VexGuestS390XState*)gst_vanilla;
756b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_SYSNO  = canonical->sysno;
757b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r2     = canonical->arg1;
758b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r3     = canonical->arg2;
759b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r4     = canonical->arg3;
760b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r5     = canonical->arg4;
761b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r6     = canonical->arg5;
762b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r7     = canonical->arg6;
763b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
764663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#elif defined(VGP_mips32_linux)
765663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VexGuestMIPS32State* gst = (VexGuestMIPS32State*)gst_vanilla;
766663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (canonical->arg8 != __NR_syscall) {
767663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r2 = canonical->sysno;
768663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r4 = canonical->arg1;
769663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r5 = canonical->arg2;
770663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r6 = canonical->arg3;
771663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r7 = canonical->arg4;
772436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      *((UInt*) (gst->guest_r29 + 16)) = canonical->arg5; // 16(guest_GPR29/sp)
773436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      *((UInt*) (gst->guest_r29 + 20)) = canonical->arg6; // 20(sp)
774663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   } else {
775663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      canonical->arg8 = 0;
776663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r2 = __NR_syscall;
777663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r4 = canonical->sysno;
778663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r5 = canonical->arg1;
779663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r6 = canonical->arg2;
780663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r7 = canonical->arg3;
781436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      *((UInt*) (gst->guest_r29 + 16)) = canonical->arg4; // 16(guest_GPR29/sp)
782436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      *((UInt*) (gst->guest_r29 + 20)) = canonical->arg5; // 20(sp)
783436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      *((UInt*) (gst->guest_r29 + 24)) = canonical->arg6; // 24(sp)
784663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
785436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
786436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#elif defined(VGP_mips64_linux)
787436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexGuestMIPS64State* gst = (VexGuestMIPS64State*)gst_vanilla;
788436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_r2 = canonical->sysno;
789436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_r4 = canonical->arg1;
790436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_r5 = canonical->arg2;
791436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_r6 = canonical->arg3;
792436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_r7 = canonical->arg4;
793436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_r8 = canonical->arg5;
794436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   gst->guest_r9 = canonical->arg6;
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "putSyscallArgsIntoGuestState: unknown arch"
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid getSyscallStatusFromGuestState ( /*OUT*/SyscallStatus*     canonical,
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      /*IN*/ VexGuestArchState* gst_vanilla )
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux)
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_x86_linux)( gst->guest_EAX );
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux)
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_amd64_linux)( gst->guest_RAX );
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc32_linux)
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC32State* gst   = (VexGuestPPC32State*)gst_vanilla;
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt                cr    = LibVEX_GuestPPC32_get_CR( gst );
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt                cr0so = (cr >> 28) & 1;
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_ppc32_linux)( gst->guest_GPR3, cr0so );
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc64_linux)
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC64State* gst   = (VexGuestPPC64State*)gst_vanilla;
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt                cr    = LibVEX_GuestPPC64_get_CR( gst );
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt                cr0so = (cr >> 28) & 1;
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_ppc64_linux)( gst->guest_GPR3, cr0so );
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_arm_linux)
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_arm_linux)( gst->guest_R0 );
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
833436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGP_arm64_linux)
834436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexGuestARM64State* gst = (VexGuestARM64State*)gst_vanilla;
835436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->sres = VG_(mk_SysRes_arm64_linux)( gst->guest_X0 );
836436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->what = SsComplete;
837436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
838663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_mips32_linux)
839663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VexGuestMIPS32State* gst = (VexGuestMIPS32State*)gst_vanilla;
840663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   UInt                v0 = gst->guest_r2;    // v0
841663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   UInt                v1 = gst->guest_r3;    // v1
842663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   UInt                a3 = gst->guest_r7;    // a3
843663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   canonical->sres = VG_(mk_SysRes_mips32_linux)( v0, v1, a3 );
844663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   canonical->what = SsComplete;
845663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
846436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGP_mips64_linux)
847436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexGuestMIPS64State* gst = (VexGuestMIPS64State*)gst_vanilla;
848436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ULong                v0 = gst->guest_r2;    // v0
849436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ULong                v1 = gst->guest_r3;    // v1
850436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   ULong                a3 = gst->guest_r7;    // a3
851436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->sres = VG_(mk_SysRes_mips64_linux)(v0, v1, a3);
852436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   canonical->what = SsComplete;
853436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_x86_darwin)
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt carry = 1 & LibVEX_GuestX86_get_eflags(gst);
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt err = 0;
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt wLO = 0;
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt wHI = 0;
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gst->guest_SC_CLASS) {
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_UNIX:
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // int $0x80 = Unix, 64-bit result
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         err = carry;
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_EAX;
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wHI = gst->guest_EDX;
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MACH:
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // int $0x81 = Mach, 32-bit result
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_EAX;
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MDEP:
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // int $0x82 = mdep, 32-bit result
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_EAX;
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_x86_darwin)(
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        gst->guest_SC_CLASS, err ? True : False,
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        wHI, wLO
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_darwin)
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong carry = 1 & LibVEX_GuestAMD64_get_rflags(gst);
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong err = 0;
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong wLO = 0;
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong wHI = 0;
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gst->guest_SC_CLASS) {
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_UNIX:
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // syscall = Unix, 128-bit result
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         err = carry;
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_RAX;
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wHI = gst->guest_RDX;
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MACH:
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // syscall = Mach, 64-bit result
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_RAX;
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MDEP:
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // syscall = mdep, 64-bit result
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_RAX;
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_amd64_darwin)(
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        gst->guest_SC_CLASS, err ? True : False,
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        wHI, wLO
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
918b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGP_s390x_linux)
919b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VexGuestS390XState* gst   = (VexGuestS390XState*)gst_vanilla;
920b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->sres = VG_(mk_SysRes_s390x_linux)( gst->guest_r2 );
921b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->what = SsComplete;
922b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "getSyscallStatusFromGuestState: unknown arch"
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid putSyscallStatusIntoGuestState ( /*IN*/ ThreadId tid,
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      /*IN*/ SyscallStatus*     canonical,
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      /*OUT*/VexGuestArchState* gst_vanilla )
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux)
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(canonical->sres)) {
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This isn't exactly right, in that really a Failure with res
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         not in the range 1 .. 4095 is unrepresentable in the
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Linux-x86 scheme.  Oh well. */
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_EAX = - (Int)sr_Err(canonical->sres);
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_EAX = sr_Res(canonical->sres);
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_x86_EAX, sizeof(UWord) );
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux)
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(canonical->sres)) {
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This isn't exactly right, in that really a Failure with res
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         not in the range 1 .. 4095 is unrepresentable in the
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Linux-amd64 scheme.  Oh well. */
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_RAX = - (Long)sr_Err(canonical->sres);
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_RAX = sr_Res(canonical->sres);
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_amd64_RAX, sizeof(UWord) );
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc32_linux)
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt old_cr = LibVEX_GuestPPC32_get_CR(gst);
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(canonical->sres)) {
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set CR0.SO */
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LibVEX_GuestPPC32_put_CR( old_cr | (1<<28), gst );
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_GPR3 = sr_Err(canonical->sres);
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* clear CR0.SO */
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LibVEX_GuestPPC32_put_CR( old_cr & ~(1<<28), gst );
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_GPR3 = sr_Res(canonical->sres);
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_ppc32_GPR3, sizeof(UWord) );
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_ppc32_CR0_0, sizeof(UChar) );
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc64_linux)
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt old_cr = LibVEX_GuestPPC64_get_CR(gst);
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(canonical->sres)) {
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set CR0.SO */
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LibVEX_GuestPPC64_put_CR( old_cr | (1<<28), gst );
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_GPR3 = sr_Err(canonical->sres);
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* clear CR0.SO */
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LibVEX_GuestPPC64_put_CR( old_cr & ~(1<<28), gst );
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_GPR3 = sr_Res(canonical->sres);
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_ppc64_GPR3, sizeof(UWord) );
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_ppc64_CR0_0, sizeof(UChar) );
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_arm_linux)
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(canonical->sres)) {
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This isn't exactly right, in that really a Failure with res
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         not in the range 1 .. 4095 is unrepresentable in the
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Linux-arm scheme.  Oh well. */
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_R0 = - (Int)sr_Err(canonical->sres);
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_R0 = sr_Res(canonical->sres);
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_arm_R0, sizeof(UWord) );
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1011436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGP_arm64_linux)
1012436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexGuestARM64State* gst = (VexGuestARM64State*)gst_vanilla;
1013436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(canonical->what == SsComplete);
1014436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sr_isError(canonical->sres)) {
1015436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* This isn't exactly right, in that really a Failure with res
1016436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         not in the range 1 .. 4095 is unrepresentable in the
1017436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         Linux-arm64 scheme.  Oh well. */
1018436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      gst->guest_X0 = - (Long)sr_Err(canonical->sres);
1019436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else {
1020436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      gst->guest_X0 = sr_Res(canonical->sres);
1021436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
1022436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1023436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             OFFSET_arm64_X0, sizeof(UWord) );
1024436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_x86_darwin)
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres = canonical->sres;
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Unfortunately here we have to break abstraction and look
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      directly inside 'res', in order to decide what to do. */
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sres._mode) {
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_MACH: // int $0x81 = Mach, 32-bit result
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_MDEP: // int $0x82 = mdep, 32-bit result
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_EAX = sres._wLO;
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_x86_EAX, sizeof(UInt) );
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_UNIX_OK:  // int $0x80 = Unix, 64-bit result
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_UNIX_ERR: // int $0x80 = Unix, 64-bit error
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_EAX = sres._wLO;
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_x86_EAX, sizeof(UInt) );
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_EDX = sres._wHI;
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_x86_EDX, sizeof(UInt) );
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         LibVEX_GuestX86_put_eflag_c( sres._mode==SysRes_UNIX_ERR ? 1 : 0,
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      gst );
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // GrP fixme sets defined for entire eflags, not just bit c
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // DDD: this breaks exp-ptrcheck.
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   offsetof(VexGuestX86State, guest_CC_DEP1), sizeof(UInt) );
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_darwin)
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres = canonical->sres;
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Unfortunately here we have to break abstraction and look
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      directly inside 'res', in order to decide what to do. */
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sres._mode) {
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_MACH: // syscall = Mach, 64-bit result
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_MDEP: // syscall = mdep, 64-bit result
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_RAX = sres._wLO;
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_amd64_RAX, sizeof(ULong) );
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_UNIX_OK:  // syscall = Unix, 128-bit result
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_UNIX_ERR: // syscall = Unix, 128-bit error
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_RAX = sres._wLO;
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_amd64_RAX, sizeof(ULong) );
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_RDX = sres._wHI;
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_amd64_RDX, sizeof(ULong) );
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         LibVEX_GuestAMD64_put_rflag_c( sres._mode==SysRes_UNIX_ERR ? 1 : 0,
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        gst );
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // GrP fixme sets defined for entire rflags, not just bit c
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // DDD: this breaks exp-ptrcheck.
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   offsetof(VexGuestAMD64State, guest_CC_DEP1), sizeof(ULong) );
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1091b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGP_s390x_linux)
1092b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VexGuestS390XState* gst = (VexGuestS390XState*)gst_vanilla;
1093b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(canonical->what == SsComplete);
1094b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (sr_isError(canonical->sres)) {
1095b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      gst->guest_r2 = - (Long)sr_Err(canonical->sres);
1096b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
1097b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      gst->guest_r2 = sr_Res(canonical->sres);
1098b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1099b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1100663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#  elif defined(VGP_mips32_linux)
1101663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VexGuestMIPS32State* gst = (VexGuestMIPS32State*)gst_vanilla;
1102663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   vg_assert(canonical->what == SsComplete);
1103663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   if (sr_isError(canonical->sres)) {
1104663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r2 = (Int)sr_Err(canonical->sres);
1105663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r7 = (Int)sr_Err(canonical->sres);
1106663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   } else {
1107663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r2 = sr_Res(canonical->sres);
1108663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r3 = sr_ResEx(canonical->sres);
1109663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      gst->guest_r7 = (Int)sr_Err(canonical->sres);
1110663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
1111663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1112663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng             OFFSET_mips32_r2, sizeof(UWord) );
1113663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1114663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng             OFFSET_mips32_r3, sizeof(UWord) );
1115663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1116663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng             OFFSET_mips32_r7, sizeof(UWord) );
1117663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1118436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#  elif defined(VGP_mips64_linux)
1119436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VexGuestMIPS64State* gst = (VexGuestMIPS64State*)gst_vanilla;
1120436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   vg_assert(canonical->what == SsComplete);
1121436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (sr_isError(canonical->sres)) {
1122436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      gst->guest_r2 = (Int)sr_Err(canonical->sres);
1123436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      gst->guest_r7 = (Int)sr_Err(canonical->sres);
1124436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   } else {
1125436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      gst->guest_r2 = sr_Res(canonical->sres);
1126436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      gst->guest_r3 = sr_ResEx(canonical->sres);
1127436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      gst->guest_r7 = (Int)sr_Err(canonical->sres);
1128436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
1129436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1130436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             OFFSET_mips64_r2, sizeof(UWord) );
1131436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1132436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             OFFSET_mips64_r3, sizeof(UWord) );
1133436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
1134436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov             OFFSET_mips64_r7, sizeof(UWord) );
1135436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "putSyscallStatusIntoGuestState: unknown arch"
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Tell me the offsets in the guest state of the syscall params, so
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that the scalar argument checkers don't have to have this info
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hardwired. */
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid getSyscallArgLayout ( /*OUT*/SyscallArgLayout* layout )
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1149436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   VG_(bzero_inline)(layout, sizeof(*layout));
1150436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_x86_linux)
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_x86_EAX;
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_x86_EBX;
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_x86_ECX;
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_x86_EDX;
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_x86_ESI;
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_x86_EDI;
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_x86_EBP;
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg7  = -1; /* impossible value */
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg8  = -1; /* impossible value */
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_linux)
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_amd64_RAX;
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_amd64_RDI;
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_amd64_RSI;
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_amd64_RDX;
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_amd64_R10;
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_amd64_R8;
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_amd64_R9;
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg7  = -1; /* impossible value */
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg8  = -1; /* impossible value */
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc32_linux)
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_ppc32_GPR0;
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_ppc32_GPR3;
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_ppc32_GPR4;
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_ppc32_GPR5;
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_ppc32_GPR6;
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_ppc32_GPR7;
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_ppc32_GPR8;
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg7  = -1; /* impossible value */
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg8  = -1; /* impossible value */
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc64_linux)
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_ppc64_GPR0;
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_ppc64_GPR3;
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_ppc64_GPR4;
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_ppc64_GPR5;
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_ppc64_GPR6;
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_ppc64_GPR7;
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_ppc64_GPR8;
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg7  = -1; /* impossible value */
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg8  = -1; /* impossible value */
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_arm_linux)
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_arm_R7;
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_arm_R0;
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_arm_R1;
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_arm_R2;
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_arm_R3;
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_arm_R4;
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_arm_R5;
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg7  = -1; /* impossible value */
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg8  = -1; /* impossible value */
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1206436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#elif defined(VGP_arm64_linux)
1207436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_sysno  = OFFSET_arm64_X8;
1208436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg1   = OFFSET_arm64_X0;
1209436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg2   = OFFSET_arm64_X1;
1210436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg3   = OFFSET_arm64_X2;
1211436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg4   = OFFSET_arm64_X3;
1212436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg5   = OFFSET_arm64_X4;
1213436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg6   = OFFSET_arm64_X5;
1214436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->uu_arg7  = -1; /* impossible value */
1215436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->uu_arg8  = -1; /* impossible value */
1216436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1217663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#elif defined(VGP_mips32_linux)
1218663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   layout->o_sysno  = OFFSET_mips32_r2;
1219663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   layout->o_arg1   = OFFSET_mips32_r4;
1220663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   layout->o_arg2   = OFFSET_mips32_r5;
1221663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   layout->o_arg3   = OFFSET_mips32_r6;
1222663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   layout->o_arg4   = OFFSET_mips32_r7;
1223663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   layout->s_arg5   = sizeof(UWord) * 4;
1224663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   layout->s_arg6   = sizeof(UWord) * 5;
1225663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   layout->uu_arg7  = -1; /* impossible value */
1226663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   layout->uu_arg8  = -1; /* impossible value */
1227663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
1228436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#elif defined(VGP_mips64_linux)
1229436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_sysno  = OFFSET_mips64_r2;
1230436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg1   = OFFSET_mips64_r4;
1231436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg2   = OFFSET_mips64_r5;
1232436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg3   = OFFSET_mips64_r6;
1233436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg4   = OFFSET_mips64_r7;
1234436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg5   = OFFSET_mips64_r8;
1235436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->o_arg6   = OFFSET_mips64_r9;
1236436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->uu_arg7  = -1; /* impossible value */
1237436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   layout->uu_arg8  = -1; /* impossible value */
1238436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_x86_darwin)
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_x86_EAX;
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // syscall parameters are on stack in C convention
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg1   = sizeof(UWord) * 1;
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg2   = sizeof(UWord) * 2;
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg3   = sizeof(UWord) * 3;
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg4   = sizeof(UWord) * 4;
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg5   = sizeof(UWord) * 5;
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg6   = sizeof(UWord) * 6;
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg7   = sizeof(UWord) * 7;
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg8   = sizeof(UWord) * 8;
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_darwin)
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_amd64_RAX;
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_amd64_RDI;
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_amd64_RSI;
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_amd64_RDX;
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_amd64_RCX;
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_amd64_R8;
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_amd64_R9;
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg7   = sizeof(UWord) * 1;
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg8   = sizeof(UWord) * 2;
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1262b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined(VGP_s390x_linux)
1263b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_sysno  = OFFSET_s390x_SYSNO;
1264b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg1   = OFFSET_s390x_r2;
1265b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg2   = OFFSET_s390x_r3;
1266b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg3   = OFFSET_s390x_r4;
1267b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg4   = OFFSET_s390x_r5;
1268b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg5   = OFFSET_s390x_r6;
1269b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg6   = OFFSET_s390x_r7;
1270b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->uu_arg7  = -1; /* impossible value */
1271b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->uu_arg8  = -1; /* impossible value */
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "getSyscallLayout: unknown arch"
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The main driver logic
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Finding the handlers for a given syscall, or faking up one
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   when no handler is found. */
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid bad_before ( ThreadId              tid,
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  SyscallArgLayout*     layout,
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*MOD*/SyscallArgs*   args,
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*OUT*/SyscallStatus* status,
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*OUT*/UWord*         flags )
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dmsg)("WARNING: unhandled syscall: %s\n",
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_SYSNUM_STRING_EXTRA(args->sysno));
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 1) {
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dmsg)("You may be able to write your own handler.\n");
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dmsg)("Read the file README_MISSING_SYSCALL_OR_IOCTL.\n");
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dmsg)("Nevertheless we consider this a bug.  Please report\n");
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dmsg)("it at http://valgrind.org/support/bug_reports.html.\n");
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SET_STATUS_Failure(VKI_ENOSYS);
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SyscallTableEntry bad_sys =
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { bad_before, NULL };
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic const SyscallTableEntry* get_syscall_entry ( Int syscallno )
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const SyscallTableEntry* sys = NULL;
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sys = ML_(get_linux_syscall_entry)( syscallno );
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int idx = VG_DARWIN_SYSNO_INDEX(syscallno);
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (VG_DARWIN_SYSNO_CLASS(syscallno)) {
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VG_DARWIN_SYSCALL_CLASS_UNIX:
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (idx >= 0 && idx < ML_(syscall_table_size) &&
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ML_(syscall_table)[idx].before != NULL)
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sys = &ML_(syscall_table)[idx];
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VG_DARWIN_SYSCALL_CLASS_MACH:
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (idx >= 0 && idx < ML_(mach_trap_table_size) &&
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ML_(mach_trap_table)[idx].before != NULL)
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sys = &ML_(mach_trap_table)[idx];
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VG_DARWIN_SYSCALL_CLASS_MDEP:
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (idx >= 0 && idx < ML_(mdep_trap_table_size) &&
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ML_(mdep_trap_table)[idx].before != NULL)
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sys = &ML_(mdep_trap_table)[idx];
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0);
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sys == NULL  ? &bad_sys  : sys;
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add and remove signals from mask so that we end up telling the
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   kernel the state we actually want rather than what the client
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   wants. */
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void sanitize_client_sigmask(vki_sigset_t *mask)
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(mask, VKI_SIGKILL);
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(mask, VKI_SIGSTOP);
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(mask, VG_SIGVGKILL); /* never block */
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SyscallArgs   orig_args;
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SyscallArgs   args;
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SyscallStatus status;
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UWord         flags;
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallInfo;
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSyscallInfo syscallInfo[VG_N_THREADS];
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The scheduler needs to be able to zero out these records after a
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fork, hence this is exported from m_syswrap. */
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(clear_syscallInfo) ( Int tid )
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 0 && tid < VG_N_THREADS);
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)( & syscallInfo[tid], 0, sizeof( syscallInfo[tid] ));
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscallInfo[tid].status.what = SsIdle;
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ensure_initialised ( void )
1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Bool init_done = False;
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (init_done)
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_done = True;
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < VG_N_THREADS; i++) {
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(clear_syscallInfo)( i );
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- This is the main function of this file. --- */
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(client_syscall) ( ThreadId tid, UInt trc )
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word                     sysno;
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState*             tst;
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const SyscallTableEntry* ent;
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallArgLayout         layout;
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallInfo*             sci;
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ensure_initialised();
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 1 && tid < VG_N_THREADS);
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst = VG_(get_ThreadState)(tid);
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* BEGIN ensure root thread's stack is suitably mapped */
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* In some rare circumstances, we may do the syscall without the
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bottom page of the stack being mapped, because the stack pointer
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      was moved down just a few instructions before the syscall
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      instruction, and there have been no memory references since
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      then, that would cause a call to VG_(extend_stack) to have
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      happened.
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      In native execution that's OK: the kernel automagically extends
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the stack's mapped area down to cover the stack pointer (or sp -
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      redzone, really).  In simulated normal execution that's OK too,
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      since any signals we get from accessing below the mapped area of
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the (guest's) stack lead us to VG_(extend_stack), where we
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      simulate the kernel's stack extension logic.  But that leaves
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the problem of entering a syscall with the SP unmapped.  Because
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the kernel doesn't know that the segment immediately above SP is
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      supposed to be a grow-down segment, it causes the syscall to
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fail, and thereby causes a divergence between native behaviour
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (syscall succeeds) and simulated behaviour (syscall fails).
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      This is quite a rare failure mode.  It has only been seen
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      affecting calls to sys_readlink on amd64-linux, and even then it
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      requires a certain code sequence around the syscall to trigger
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      it.  Here is one:
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      extern int my_readlink ( const char* path );
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      asm(
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ".text\n"
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ".globl my_readlink\n"
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "my_readlink:\n"
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tsubq    $0x1008,%rsp\n"
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tmovq    %rdi,%rdi\n"              // path is in rdi
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tmovq    %rsp,%rsi\n"              // &buf[0] -> rsi
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tmovl    $0x1000,%edx\n"           // sizeof(buf) in rdx
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tmovl    $"__NR_READLINK",%eax\n"  // syscall number
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tsyscall\n"
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\taddq    $0x1008,%rsp\n"
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tret\n"
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ".previous\n"
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      For more details, see bug #156404
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (https://bugs.kde.org/show_bug.cgi?id=156404).
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The fix is actually very simple.  We simply need to call
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(extend_stack) for this thread, handing it the lowest
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      possible valid address for stack (sp - redzone), to ensure the
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pages all the way down to that address, are mapped.  Because
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      this is a potentially expensive and frequent operation, we
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      filter in two ways:
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      First, only the main thread (tid=1) has a growdown stack.  So
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ignore all others.  It is conceivable, although highly unlikely,
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that the main thread exits, and later another thread is
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allocated tid=1, but that's harmless, I believe;
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(extend_stack) will do nothing when applied to a non-root
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thread.
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Secondly, first call VG_(am_find_nsegment) directly, to see if
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the page holding (sp - redzone) is mapped correctly.  If so, do
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nothing.  This is almost always the case.  VG_(extend_stack)
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      calls VG_(am_find_nsegment) twice, so this optimisation -- and
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that's all it is -- more or less halves the number of calls to
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(am_find_nsegment) required.
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      TODO: the test "seg->kind == SkAnonC" is really inadequate,
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      because although it tests whether the segment is mapped
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      _somehow_, it doesn't check that it has the right permissions
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (r,w, maybe x) ?  We could test that here, but it will also be
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      necessary to fix the corresponding test in VG_(extend_stack).
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      All this guff is of course Linux-specific.  Hence the ifdef.
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (tid == 1/*ROOT THREAD*/) {
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr     stackMin   = VG_(get_SP)(tid) - VG_STACK_REDZONE_SZB;
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      NSegment const* seg = VG_(am_find_nsegment)(stackMin);
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (seg && seg->kind == SkAnonC) {
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* stackMin is already mapped.  Nothing to do. */
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (void)VG_(extend_stack)( stackMin,
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  tst->client_stack_szB );
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* END ensure root thread's stack is suitably mapped */
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First off, get the syscall args and number.  This is a
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      platform-dependent action. */
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci = & syscallInfo[tid];
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what == SsIdle);
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   getSyscallArgsFromGuestState( &sci->orig_args, &tst->arch.vex, trc );
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy .orig_args to .args.  The pre-handler may modify .args, but
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      we want to keep the originals too, just in case. */
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->args = sci->orig_args;
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Save the syscall number in the thread state in case the syscall
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is interrupted by a signal. */
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sysno = sci->orig_args.sysno;
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1511b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* It's sometimes useful, as a crude debugging hack, to get a
1512b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      stack trace at each (or selected) syscalls. */
1513b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (0 && sysno == __NR_ioctl) {
1514b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)("\nioctl:\n");
1515b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(get_and_pp_StackTrace)(tid, 10);
1516b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)("\n");
1517b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1518b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_darwin)
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Record syscall class.  But why?  Because the syscall might be
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interrupted by a signal, and in the signal handler (which will
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      be m_signals.async_signalhandler) we will need to build a SysRes
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reflecting the syscall return result.  In order to do that we
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      need to know the syscall class.  Hence stash it in the guest
1525b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      state of this thread.  This madness is not needed on Linux
1526b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      because it only has a single syscall return convention and so
1527b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      there is no ambiguity involved in converting the post-signal
1528b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      machine state into a SysRes. */
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->arch.vex.guest_SC_CLASS = VG_DARWIN_SYSNO_CLASS(sysno);
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The default what-to-do-next thing is hand the syscall to the
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      kernel, so we pre-set that here.  Set .sres to something
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      harmless looking (is irrelevant because .what is not
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SsComplete.) */
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status.what = SsHandToKernel;
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status.sres = VG_(mk_SysRes_Error)(0);
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->flags       = 0;
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fetch the syscall's handlers.  If no handlers exist for this
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      syscall, we are given dummy handlers which force an immediate
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return with ENOSYS. */
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ent = get_syscall_entry(sysno);
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fetch the layout information, which tells us where in the guest
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      state the syscall args reside.  This is a platform-dependent
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      action.  This info is needed so that the scalar syscall argument
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      checks (PRE_REG_READ calls) know which bits of the guest state
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      they need to inspect. */
1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   getSyscallArgLayout( &layout );
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure the tmp signal mask matches the real signal mask;
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sigsuspend may change this. */
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(iseqsigset)(&tst->sig_mask, &tst->tmp_sig_mask));
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Right, we're finally ready to Party.  Call the pre-handler and
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      see what we get back.  At this point:
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        sci->status.what  is Unset (we don't know yet).
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        sci->orig_args    contains the original args.
1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        sci->args         is the same as sci->orig_args.
1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        sci->flags        is zero.
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRINT("SYSCALL[%d,%d](%s) ",
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(getpid)(), tid, VG_SYSNUM_STRING(sysno));
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do any pre-syscall actions */
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(needs).syscall_wrapper) {
1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UWord tmpv[8];
1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[0] = sci->orig_args.arg1;
1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[1] = sci->orig_args.arg2;
1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[2] = sci->orig_args.arg3;
1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[3] = sci->orig_args.arg4;
1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[4] = sci->orig_args.arg5;
1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[5] = sci->orig_args.arg6;
1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[6] = sci->orig_args.arg7;
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[7] = sci->orig_args.arg8;
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TDICT_CALL(tool_pre_syscall, tid, sysno,
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &tmpv[0], sizeof(tmpv)/sizeof(tmpv[0]));
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ent);
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ent->before);
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (ent->before)( tid,
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  &layout,
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  &sci->args, &sci->status, &sci->flags );
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The pre-handler may have modified:
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sci->args
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sci->status
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sci->flags
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      All else remains unchanged.
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Although the args may be modified, pre handlers are not allowed
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to change the syscall number.
1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now we proceed according to what the pre-handler decided. */
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what == SsHandToKernel
1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             || sci->status.what == SsComplete);
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->args.sysno == sci->orig_args.sysno);
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->status.what == SsComplete && !sr_isError(sci->status.sres)) {
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The pre-handler completed the syscall itself, declaring
1604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         success. */
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sci->flags & SfNoWriteResult) {
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         PRINT(" --> [pre-success] NoWriteResult");
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         PRINT(" --> [pre-success] Success(0x%llx:0x%llx)",
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (ULong)sr_ResHI(sci->status.sres),
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (ULong)sr_Res(sci->status.sres));
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* In this case the allowable flags are to ask for a signal-poll
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and/or a yield after the call.  Changing the args isn't
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         allowed. */
1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0 == (sci->flags
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      & ~(SfPollAfter | SfYieldAfter | SfNoWriteResult)));
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(eq_SyscallArgs(&sci->args, &sci->orig_args));
1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->status.what == SsComplete && sr_isError(sci->status.sres)) {
1622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The pre-handler decided to fail syscall itself. */
1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      PRINT(" --> [pre-fail] Failure(0x%llx)", (ULong)sr_Err(sci->status.sres));
1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* In this case, the pre-handler is also allowed to ask for the
1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         post-handler to be run anyway.  Changing the args is not
1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         allowed. */
1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0 == (sci->flags & ~(SfMayBlock | SfPostOnFail | SfPollAfter)));
1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(eq_SyscallArgs(&sci->args, &sci->orig_args));
1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->status.what != SsHandToKernel) {
1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* huh?! */
1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0);
1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else /* (sci->status.what == HandToKernel) */ {
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Ok, this is the usual case -- and the complicated one.  There
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         are two subcases: sync and async.  async is the general case
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and is to be used when there is any possibility that the
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         syscall might block [a fact that the pre-handler must tell us
1642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         via the sci->flags field.]  Because the tidying-away /
1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         context-switch overhead of the async case could be large, if
1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we are sure that the syscall will not block, we fast-track it
1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         by doing it directly in this thread, which is a lot
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         simpler. */
1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Check that the given flags are allowable: MayBlock, PollAfter
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and PostOnFail are ok. */
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0 == (sci->flags & ~(SfMayBlock | SfPostOnFail | SfPollAfter)));
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sci->flags & SfMayBlock) {
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Syscall may block, so run it asynchronously */
1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vki_sigset_t mask;
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         PRINT(" --> [async] ... \n");
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask = tst->sig_mask;
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sanitize_client_sigmask(&mask);
1661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Gack.  More impedance matching.  Copy the possibly
1663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            modified syscall args back into the guest state. */
1664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* JRS 2009-Mar-16: if the syscall args are possibly modified,
1665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            then this assertion is senseless:
1666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              vg_assert(eq_SyscallArgs(&sci->args, &sci->orig_args));
1667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            The case that exposed it was sys_posix_spawn on Darwin,
1668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            which heavily modifies its arguments but then lets the call
1669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            go through anyway, with SfToBlock set, hence we end up here. */
1670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putSyscallArgsIntoGuestState( &sci->args, &tst->arch.vex );
1671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Drop the bigLock */
1673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(release_BigLock)(tid, VgTs_WaitSys, "VG_(client_syscall)[async]");
1674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Urr.  We're now in a race against other threads trying to
1675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            acquire the bigLock.  I guess that doesn't matter provided
1676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            that do_syscall_for_client only touches thread-local
1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            state. */
1678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Do the call, which operates directly on the guest state,
1680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            not on our abstracted copies of the args/result. */
1681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_syscall_for_client(sysno, tst, &mask);
1682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* do_syscall_for_client may not return if the syscall was
1684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            interrupted by a signal.  In that case, flow of control is
1685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            first to m_signals.async_sighandler, which calls
1686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(fixup_guest_state_after_syscall_interrupted), which
1687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fixes up the guest state, and possibly calls
1688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(post_syscall).  Once that's done, control drops back
1689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            to the scheduler.  */
1690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Darwin: do_syscall_for_client may not return if the
1692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            syscall was workq_ops(WQOPS_THREAD_RETURN) and the kernel
1693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            responded by starting the thread at wqthread_hijack(reuse=1)
1694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (to run another workqueue item). In that case, wqthread_hijack
1695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            calls ML_(wqthread_continue), which is similar to
1696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(fixup_guest_state_after_syscall_interrupted). */
1697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Reacquire the lock */
1699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(acquire_BigLock)(tid, "VG_(client_syscall)[async]");
1700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Even more impedance matching.  Extract the syscall status
1702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            from the guest state. */
1703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         getSyscallStatusFromGuestState( &sci->status, &tst->arch.vex );
1704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(sci->status.what == SsComplete);
1705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Be decorative, if required. */
1707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(clo_trace_syscalls)) {
1708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool failed = sr_isError(sci->status.sres);
1709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (failed) {
1710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               PRINT("SYSCALL[%d,%d](%s) ... [async] --> Failure(0x%llx)",
1711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     VG_(getpid)(), tid, VG_SYSNUM_STRING(sysno),
1712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_Err(sci->status.sres));
1713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               PRINT("SYSCALL[%d,%d](%s) ... [async] --> "
1715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     "Success(0x%llx:0x%llx)",
1716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     VG_(getpid)(), tid, VG_SYSNUM_STRING(sysno),
1717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_ResHI(sci->status.sres),
1718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_Res(sci->status.sres) );
1719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* run the syscall directly */
1725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* The pre-handler may have modified the syscall args, but
1726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            since we're passing values in ->args directly to the
1727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            kernel, there's no point in flushing them back to the
1728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            guest state.  Indeed doing so could be construed as
1729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            incorrect. */
1730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SysRes sres
1731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = VG_(do_syscall)(sysno, sci->args.arg1, sci->args.arg2,
1732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     sci->args.arg3, sci->args.arg4,
1733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     sci->args.arg5, sci->args.arg6,
1734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     sci->args.arg7, sci->args.arg8 );
1735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sci->status = convert_SysRes_to_SyscallStatus(sres);
1736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Be decorative, if required. */
1738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(clo_trace_syscalls)) {
1739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool failed = sr_isError(sci->status.sres);
1740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (failed) {
1741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               PRINT("[sync] --> Failure(0x%llx)",
1742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_Err(sci->status.sres) );
1743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               PRINT("[sync] --> Success(0x%llx:0x%llx)",
1745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_ResHI(sci->status.sres),
1746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_Res(sci->status.sres) );
1747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what == SsComplete);
1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Dump the syscall result back in the guest state.  This is
1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a platform-specific action. */
1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!(sci->flags & SfNoWriteResult))
1759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putSyscallStatusIntoGuestState( tid, &sci->status, &tst->arch.vex );
1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Situation now:
1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - the guest state is now correctly modified following the syscall
1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - modified args, original args and syscall status are still
1764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        available in the syscallInfo[] entry for this syscall.
1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Now go on to do the post-syscall actions (read on down ..)
1767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRINT(" ");
1769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(post_syscall)(tid);
1770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRINT("\n");
1771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Perform post syscall actions.  The expected state on entry is
1775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   precisely as at the end of VG_(client_syscall), that is:
1776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - guest state up to date following the syscall
1778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - modified args, original args and syscall status are still
1779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     available in the syscallInfo[] entry for this syscall.
1780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - syscall status matches what's in the guest state.
1781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   There are two ways to get here: the normal way -- being called by
1783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(client_syscall), and the unusual way, from
1784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(fixup_guest_state_after_syscall_interrupted).
1785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Darwin: there's a third way, ML_(wqthread_continue).
1786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(post_syscall) (ThreadId tid)
1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallInfo*             sci;
1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const SyscallTableEntry* ent;
1791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallStatus            test_status;
1792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState*             tst;
1793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word sysno;
1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Preliminaries */
1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 1 && tid < VG_N_THREADS);
1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
1799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst = VG_(get_ThreadState)(tid);
1801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci = & syscallInfo[tid];
1802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* m_signals.sigvgkill_handler might call here even when not in
1804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a syscall. */
1805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->status.what == SsIdle || sci->status.what == SsHandToKernel) {
1806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sci->status.what = SsIdle;
1807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
1808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Validate current syscallInfo entry.  In particular we require
1811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that the current .status matches what's actually in the guest
1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      state.  At least in the normal case where we have actually
1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      previously written the result into the guest state. */
1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what == SsComplete);
1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   getSyscallStatusFromGuestState( &test_status, &tst->arch.vex );
1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!(sci->flags & SfNoWriteResult))
1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(eq_SyscallStatus( &sci->status, &test_status ));
1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Failure of the above assertion on Darwin can indicate a problem
1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      in the syscall wrappers that pre-fail or pre-succeed the
1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      syscall, by calling SET_STATUS_Success or SET_STATUS_Failure,
1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when they really should call SET_STATUS_from_SysRes.  The former
1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      create a UNIX-class syscall result on Darwin, which may not be
1824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      correct for the syscall; if that's the case then this assertion
1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fires.  See PRE(thread_fast_set_cthread_self) for an example.  On
1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      non-Darwin platforms this assertion is should never fail, and this
1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      comment is completely irrelevant. */
1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Ok, looks sane */
1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Get the system call number.  Because the pre-handler isn't
1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allowed to mess with it, it should be the same for both the
1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      original and potentially-modified args. */
1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->args.sysno == sci->orig_args.sysno);
1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sysno = sci->args.sysno;
1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ent = get_syscall_entry(sysno);
1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* pre: status == Complete (asserted above) */
1838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Consider either success or failure.  Now run the post handler if:
1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - it exists, and
1840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - Success or (Failure and PostOnFail is set)
1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ent->after
1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && ((!sr_isError(sci->status.sres))
1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || (sr_isError(sci->status.sres)
1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               && (sci->flags & SfPostOnFail) ))) {
1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (ent->after)( tid, &sci->args, &sci->status );
1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Because the post handler might have changed the status (eg, the
1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      post-handler for sys_open can change the result from success to
1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      failure if the kernel supplied a fd that it doesn't like), once
1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      again dump the syscall result back in the guest state.*/
1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!(sci->flags & SfNoWriteResult))
1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putSyscallStatusIntoGuestState( tid, &sci->status, &tst->arch.vex );
1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do any post-syscall actions required by the tool. */
1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(needs).syscall_wrapper) {
1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UWord tmpv[8];
1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[0] = sci->orig_args.arg1;
1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[1] = sci->orig_args.arg2;
1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[2] = sci->orig_args.arg3;
1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[3] = sci->orig_args.arg4;
1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[4] = sci->orig_args.arg5;
1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[5] = sci->orig_args.arg6;
1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[6] = sci->orig_args.arg7;
1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[7] = sci->orig_args.arg8;
1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TDICT_CALL(tool_post_syscall, tid,
1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sysno,
1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &tmpv[0], sizeof(tmpv)/sizeof(tmpv[0]),
1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sci->status.sres);
1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The syscall is done. */
1875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what == SsComplete);
1876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status.what = SsIdle;
1877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The pre/post wrappers may have concluded that pending signals
1879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      might have been created, and will have set SfPollAfter to
1880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      request a poll for them once the syscall is done. */
1881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->flags & SfPollAfter)
1882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(poll_signals)(tid);
1883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Similarly, the wrappers might have asked for a yield
1885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      afterwards. */
1886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->flags & SfYieldAfter)
1887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(vg_yield)();
1888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
1892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Dealing with syscalls which get interrupted by a signal:
1893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(fixup_guest_state_after_syscall_interrupted)
1894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
1895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Syscalls done on behalf of the client are finally handed off to the
1897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   kernel in VG_(client_syscall) above, either by calling
1898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_syscall_for_client (the async case), or by calling
1899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(do_syscall6) (the sync case).
1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If the syscall is not interrupted by a signal (it may block and
1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   later unblock, but that's irrelevant here) then those functions
1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   eventually return and so control is passed to VG_(post_syscall).
1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NB: not sure if the sync case can actually get interrupted, as it
1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   operates with all signals masked.
1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   However, the syscall may get interrupted by an async-signal.  In
1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that case do_syscall_for_client/VG_(do_syscall6) do not
1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return.  Instead we wind up in m_signals.async_sighandler.  We need
1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to fix up the guest state to make it look like the syscall was
1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   interrupted for guest.  So async_sighandler calls here, and this
1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   does the fixup.  Note that from here we wind up calling
1913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(post_syscall) too.
1914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* These are addresses within ML_(do_syscall_for_client_WRK).  See
1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscall-$PLAT.S for details.
1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1920b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if defined(VGO_linux)
1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_setup);
1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_restart);
1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_complete);
1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_committed);
1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_finished);
1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGO_darwin)
1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* Darwin requires extra uglyness */
1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_setup_MACH);
1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_restart_MACH);
1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_complete_MACH);
1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_committed_MACH);
1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_finished_MACH);
1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_setup_MDEP);
1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_restart_MDEP);
1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_complete_MDEP);
1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_committed_MDEP);
1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_finished_MDEP);
1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_setup_UNIX);
1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_restart_UNIX);
1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_complete_UNIX);
1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_committed_UNIX);
1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_finished_UNIX);
1943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
1944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# error "Unknown OS"
1945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
1946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Back up guest state to restart a system call. */
1949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ML_(fixup_guest_state_to_restart_syscall) ( ThreadArchState* arch )
1951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_x86_linux)
1953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_EIP -= 2;             // sizeof(int $0x80)
1954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure our caller is actually sane, and we're really backing
1956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      back over a syscall.
1957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      int $0x80 == CD 80
1959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar *p = (UChar *)arch->vex.guest_EIP;
1962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (p[0] != 0xcd || p[1] != 0x80)
1964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
1965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "?! restarting over syscall at %#x %02x %02x\n",
1966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      arch->vex.guest_EIP, p[0], p[1]);
1967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(p[0] == 0xcd && p[1] == 0x80);
1969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_linux)
1972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_RIP -= 2;             // sizeof(syscall)
1973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure our caller is actually sane, and we're really backing
1975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      back over a syscall.
1976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      syscall == 0F 05
1978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar *p = (UChar *)arch->vex.guest_RIP;
1981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (p[0] != 0x0F || p[1] != 0x05)
1983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
1984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "?! restarting over syscall at %#llx %02x %02x\n",
1985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      arch->vex.guest_RIP, p[0], p[1]);
1986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(p[0] == 0x0F && p[1] == 0x05);
1988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
1991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_CIA -= 4;             // sizeof(ppc32 instr)
1992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure our caller is actually sane, and we're really backing
1994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      back over a syscall.
1995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sc == 44 00 00 02
1997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar *p = (UChar *)arch->vex.guest_CIA;
2000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (p[0] != 0x44 || p[1] != 0x0 || p[2] != 0x0 || p[3] != 0x02)
2002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
2003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "?! restarting over syscall at %#llx %02x %02x %02x %02x\n",
2004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      arch->vex.guest_CIA + 0ULL, p[0], p[1], p[2], p[3]);
2005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(p[0] == 0x44 && p[1] == 0x0 && p[2] == 0x0 && p[3] == 0x2);
2007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_arm_linux)
2010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (arch->vex.guest_R15T & 1) {
2011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Thumb mode.  SVC is a encoded as
2012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   1101 1111 imm8
2013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // where imm8 is the SVC number, and we only accept 0.
2014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arch->vex.guest_R15T -= 2;   // sizeof(thumb 16 bit insn)
2015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* p     = (UChar*)(arch->vex.guest_R15T - 1);
2016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   valid = p[0] == 0 && p[1] == 0xDF;
2017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!valid) {
2018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
2019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "?! restarting over (Thumb) syscall that is not syscall "
2020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "at %#llx %02x %02x\n",
2021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      arch->vex.guest_R15T - 1ULL, p[0], p[1]);
2022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(valid);
2024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // FIXME: NOTE, this really isn't right.  We need to back up
2025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // ITSTATE to what it was before the SVC instruction, but we
2026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // don't know what it was.  At least assert that it is now
2027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // zero, because if it is nonzero then it must also have
2028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // been nonzero for the SVC itself, which means it was
2029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // conditional.  Urk.
2030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(arch->vex.guest_ITSTATE == 0);
2031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // ARM mode.  SVC is encoded as
2033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   cond 1111 imm24
2034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // where imm24 is the SVC number, and we only accept 0.
2035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arch->vex.guest_R15T -= 4;   // sizeof(arm instr)
2036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* p     = (UChar*)arch->vex.guest_R15T;
2037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   valid = p[0] == 0 && p[1] == 0 && p[2] == 0
2038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     && (p[3] & 0xF) == 0xF;
2039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!valid) {
2040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
2041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "?! restarting over (ARM) syscall that is not syscall "
2042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "at %#llx %02x %02x %02x %02x\n",
2043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      arch->vex.guest_R15T + 0ULL, p[0], p[1], p[2], p[3]);
2044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(valid);
2046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2048436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#elif defined(VGP_arm64_linux)
2049436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   arch->vex.guest_PC -= 4;             // sizeof(arm64 instr)
2050436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
2051436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Make sure our caller is actually sane, and we're really backing
2052436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      back over a syscall.
2053436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
2054436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      svc #0 == d4 00 00 01
2055436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   */
2056436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   {
2057436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      UChar *p = (UChar *)arch->vex.guest_PC;
2058436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
2059436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      if (p[0] != 0x01 || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0xD4)
2060436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         VG_(message)(
2061436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            Vg_DebugMsg,
2062436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            "?! restarting over syscall at %#llx %02x %02x %02x %02x\n",
2063436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov            arch->vex.guest_PC + 0ULL, p[0], p[1], p[2], p[3]
2064436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov          );
2065436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
2066436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      vg_assert(p[0] == 0x01 && p[1] == 0x00 && p[2] == 0x00 && p[3] == 0xD4);
2067436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
2068436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
2069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_x86_darwin)
2070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_EIP = arch->vex.guest_IP_AT_SYSCALL;
2071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure our caller is actually sane, and we're really backing
2073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      back over a syscall.
2074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      int $0x80 == CD 80
2076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      int $0x81 == CD 81
2077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      int $0x82 == CD 82
2078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sysenter  == 0F 34
2079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
2080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       UChar *p = (UChar *)arch->vex.guest_EIP;
2082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       Bool  ok = (p[0] == 0xCD && p[1] == 0x80)
2083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  || (p[0] == 0xCD && p[1] == 0x81)
2084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  || (p[0] == 0xCD && p[1] == 0x82)
2085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  || (p[0] == 0x0F && p[1] == 0x34);
2086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       if (!ok)
2087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           VG_(message)(Vg_DebugMsg,
2088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        "?! restarting over syscall at %#x %02x %02x\n",
2089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        arch->vex.guest_EIP, p[0], p[1]);
2090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       vg_assert(ok);
2091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_darwin)
2094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // DDD: #warning GrP fixme amd64 restart unimplemented
2095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
2096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2097b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined(VGP_s390x_linux)
2098b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   arch->vex.guest_IA -= 2;             // sizeof(syscall)
2099b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Make sure our caller is actually sane, and we're really backing
2101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      back over a syscall.
2102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      syscall == 0A <num>
2104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   */
2105b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   {
2106b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UChar *p = (UChar *)arch->vex.guest_IA;
2107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (p[0] != 0x0A)
2108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(message)(Vg_DebugMsg,
2109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      "?! restarting over syscall at %#llx %02x %02x\n",
2110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      arch->vex.guest_IA, p[0], p[1]);
2111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
2112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(p[0] == 0x0A);
2113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
2114663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
2115436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#elif defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
2116663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
2117663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   arch->vex.guest_PC -= 4;             // sizeof(mips instr)
2118663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
2119663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   /* Make sure our caller is actually sane, and we're really backing
2120663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      back over a syscall.
2121663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
2122663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      syscall == 00 00 00 0C
2123663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      big endian
2124663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      syscall == 0C 00 00 00
2125663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   */
2126663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   {
2127663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      UChar *p = (UChar *)(arch->vex.guest_PC);
2128663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#     if defined (VG_LITTLEENDIAN)
2129663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (p[0] != 0x0c || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0x00)
2130663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         VG_(message)(Vg_DebugMsg,
2131436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      "?! restarting over syscall at %#llx %02x %02x %02x %02x\n",
2132436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      (ULong)arch->vex.guest_PC, p[0], p[1], p[2], p[3]);
2133663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
2134663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vg_assert(p[0] == 0x0c && p[1] == 0x00 && p[2] == 0x00 && p[3] == 0x00);
2135663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#     elif defined (VG_BIGENDIAN)
2136663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x00 || p[3] != 0x0c)
2137663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng         VG_(message)(Vg_DebugMsg,
2138436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      "?! restarting over syscall at %#llx %02x %02x %02x %02x\n",
2139436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      (ULong)arch->vex.guest_PC, p[0], p[1], p[2], p[3]);
2140663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
2141663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng      vg_assert(p[0] == 0x00 && p[1] == 0x00 && p[2] == 0x00 && p[3] == 0x0c);
2142663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#     else
2143663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#        error "Unknown endianness"
2144663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng#     endif
2145663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng   }
2146663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
2147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
2148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "ML_(fixup_guest_state_to_restart_syscall): unknown plat"
2149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
2150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2152663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng
2153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
2154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Fix up the guest state when a syscall is interrupted by a signal
2155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and so has been forced to return 'sysret'.
2156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   To do this, we determine the precise state of the syscall by
2158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   looking at the (real) IP at the time the signal happened.  The
2159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscall sequence looks like:
2160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     1. unblock signals
2162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     2. perform syscall
2163663860b1408516d02ebfcb3a9999a134e6cfb223Ben Cheng     3. save result to guest state (EAX, RAX, R3+CR0.SO, R0, V0)
2164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     4. re-block signals
2165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If a signal
2167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   happens at      Then     Why?
2168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [1-2)           restart  nothing has happened (restart syscall)
2169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [2]             restart  syscall hasn't started, or kernel wants to restart
2170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [2-3)           save     syscall complete, but results not saved
2171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [3-4)           syscall complete, results saved
2172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Sometimes we never want to restart an interrupted syscall (because
2174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sigaction says not to), so we only restart if "restart" is True.
2175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This will also call VG_(post_syscall) if the syscall has actually
2177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   completed (either because it was interrupted, or because it
2178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   actually finished).  It will not call VG_(post_syscall) if the
2179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscall is set up for restart, which means that the pre-wrapper may
2180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   get called multiple times.
2181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid
2184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid,
2185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  Addr     ip,
2186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  SysRes   sres,
2187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  Bool     restart)
2188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Note that we don't know the syscall number here, since (1) in
2190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      general there's no reliable way to get hold of it short of
2191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stashing it in the guest state before the syscall, and (2) in
2192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      any case we don't need to know it for the actions done by this
2193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      routine.
2194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Furthermore, 'sres' is only used in the case where the syscall
2196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is complete, but the result has not been committed to the guest
2197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      state yet.  In any other situation it will be meaningless and
2198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      therefore ignored. */
2199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState*     tst;
2201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallStatus    canonical;
2202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadArchState* th_regs;
2203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallInfo*     sci;
2204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Compute some Booleans indicating which range we're in. */
2206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool outside_range,
2207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        in_setup_to_restart,      // [1,2) in the .S files
2208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        at_restart,               // [2]   in the .S files
2209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        in_complete_to_committed, // [3,4) in the .S files
2210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        in_committed_to_finished; // [4,5) in the .S files
2211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2212b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
2213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   outside_range
2214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ip < ML_(blksys_setup) || ip >= ML_(blksys_finished);
2215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_setup_to_restart
2216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ip >= ML_(blksys_setup) && ip < ML_(blksys_restart);
2217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   at_restart
2218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ip == ML_(blksys_restart);
2219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_complete_to_committed
2220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ip >= ML_(blksys_complete) && ip < ML_(blksys_committed);
2221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_committed_to_finished
2222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ip >= ML_(blksys_committed) && ip < ML_(blksys_finished);
2223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
2224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   outside_range
2225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      =  (ip < ML_(blksys_setup_MACH) || ip >= ML_(blksys_finished_MACH))
2226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      && (ip < ML_(blksys_setup_MDEP) || ip >= ML_(blksys_finished_MDEP))
2227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      && (ip < ML_(blksys_setup_UNIX) || ip >= ML_(blksys_finished_UNIX));
2228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_setup_to_restart
2229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      =  (ip >= ML_(blksys_setup_MACH) && ip < ML_(blksys_restart_MACH))
2230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_setup_MDEP) && ip < ML_(blksys_restart_MDEP))
2231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_setup_UNIX) && ip < ML_(blksys_restart_UNIX));
2232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   at_restart
2233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      =  (ip == ML_(blksys_restart_MACH))
2234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip == ML_(blksys_restart_MDEP))
2235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip == ML_(blksys_restart_UNIX));
2236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_complete_to_committed
2237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      =  (ip >= ML_(blksys_complete_MACH) && ip < ML_(blksys_committed_MACH))
2238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_complete_MDEP) && ip < ML_(blksys_committed_MDEP))
2239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_complete_UNIX) && ip < ML_(blksys_committed_UNIX));
2240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_committed_to_finished
2241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      =  (ip >= ML_(blksys_committed_MACH) && ip < ML_(blksys_finished_MACH))
2242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_committed_MDEP) && ip < ML_(blksys_finished_MDEP))
2243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_committed_UNIX) && ip < ML_(blksys_finished_UNIX));
2244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Wasn't that just So Much Fun?  Does your head hurt yet?  Mine does. */
2245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
2246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
2247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
2248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_signals))
2250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)( Vg_DebugMsg,
2251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "interrupted_syscall: tid=%d, ip=0x%llx, "
2252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "restart=%s, sres.isErr=%s, sres.val=%lld\n",
2253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    (Int)tid,
2254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    (ULong)ip,
2255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    restart ? "True" : "False",
2256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sr_isError(sres) ? "True" : "False",
2257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    (Long)(sr_isError(sres) ? sr_Err(sres) : sr_Res(sres)) );
2258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
2260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 1 && tid < VG_N_THREADS);
2261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
2262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst     = VG_(get_ThreadState)(tid);
2264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   th_regs = &tst->arch;
2265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci     = & syscallInfo[tid];
2266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Figure out what the state of the syscall was by examining the
2268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (real) IP at the time of the signal, and act accordingly. */
2269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (outside_range) {
2270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals))
2271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)( Vg_DebugMsg,
2272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "  not in syscall at all: hmm, very suspicious\n" );
2273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Looks like we weren't in a syscall at all.  Hmm. */
2274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(sci->status.what != SsIdle);
2275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
2276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We should not be here unless this thread had first started up
2279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the machinery for a syscall by calling VG_(client_syscall).
2280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Hence: */
2281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what != SsIdle);
2282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* now, do one of four fixup actions, depending on where the IP has
2284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      got to. */
2285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (in_setup_to_restart) {
2287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* syscall hasn't even started; go around again */
2288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals))
2289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)( Vg_DebugMsg, "  not started: restarting\n");
2290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(sci->status.what == SsHandToKernel);
2291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(fixup_guest_state_to_restart_syscall)(th_regs);
2292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (at_restart) {
2296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We're either about to run the syscall, or it was interrupted
2297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and the kernel restarted it.  Restart if asked, otherwise
2298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         EINTR it. */
2299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (restart) {
2300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(clo_trace_signals))
2301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(message)( Vg_DebugMsg, "  at syscall instr: restarting\n");
2302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(fixup_guest_state_to_restart_syscall)(th_regs);
2303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(clo_trace_signals))
2305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(message)( Vg_DebugMsg, "  at syscall instr: returning EINTR\n");
2306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         canonical = convert_SysRes_to_SyscallStatus(
2307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        VG_(mk_SysRes_Error)( VKI_EINTR )
2308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
2309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!(sci->flags & SfNoWriteResult))
2310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putSyscallStatusIntoGuestState( tid, &canonical, &th_regs->vex );
2311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sci->status = canonical;
2312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(post_syscall)(tid);
2313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (in_complete_to_committed) {
2318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Syscall complete, but result hasn't been written back yet.
2319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Write the SysRes we were supplied with back to the guest
2320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         state. */
2321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals))
2322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)( Vg_DebugMsg,
2323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "  completed, but uncommitted: committing\n");
2324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical = convert_SysRes_to_SyscallStatus( sres );
2325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(sci->flags & SfNoWriteResult))
2326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putSyscallStatusIntoGuestState( tid, &canonical, &th_regs->vex );
2327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sci->status = canonical;
2328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(post_syscall)(tid);
2329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (in_committed_to_finished) {
2333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Result committed, but the signal mask has not been restored;
2334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we expect our caller (the signal handler) will have fixed
2335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this up. */
2336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals))
2337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)( Vg_DebugMsg,
2338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "  completed and committed: nothing to do\n");
2339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      getSyscallStatusFromGuestState( &sci->status, &th_regs->vex );
2340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(sci->status.what == SsComplete);
2341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(post_syscall)(tid);
2342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(core_panic)("?? strange syscall interrupt state?");
2346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* In all cases, the syscall is now finished (even if we called
2348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(fixup_guest_state_to_restart_syscall), since that just
2349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      re-positions the guest's IP for another go at it).  So we need
2350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to record that fact. */
2351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status.what = SsIdle;
2352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_darwin)
2356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Clean up after workq_ops(WQOPS_THREAD_RETURN) jumped to wqthread_hijack.
2357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This is similar to VG_(fixup_guest_state_after_syscall_interrupted).
2358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This longjmps back to the scheduler.
2359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ML_(wqthread_continue_NORETURN)(ThreadId tid)
2360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState*     tst;
2362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallInfo*     sci;
2363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(acquire_BigLock)(tid, "wqthread_continue_NORETURN");
2365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRINT("SYSCALL[%d,%d](%s) workq_ops() starting new workqueue item\n",
2367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(getpid)(), tid, VG_SYSNUM_STRING(__NR_workq_ops));
2368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
2370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 1 && tid < VG_N_THREADS);
2371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
2372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst     = VG_(get_ThreadState)(tid);
2374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci     = & syscallInfo[tid];
2375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what != SsIdle);
2376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tst->os_state.wq_jmpbuf_valid);  // check this BEFORE post_syscall
2377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Pretend the syscall completed normally, but don't touch the thread state.
2379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status = convert_SysRes_to_SyscallStatus( VG_(mk_SysRes_Success)(0) );
2380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->flags |= SfNoWriteResult;
2381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(post_syscall)(tid);
2382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status.what = SsIdle;
2384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tst->sched_jmpbuf_valid);
2386b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_MINIMAL_LONGJMP(tst->sched_jmpbuf);
2387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* NOTREACHED */
2389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
2390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
2392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
2395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   A place to store the where-to-call-when-really-done pointer
2396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
2397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// When the final thread is done, where shall I call to shutdown the
2399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// system cleanly?  Is set once at startup (in m_main) and never
2400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// changes after that.  Is basically a pointer to the exit
2401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// continuation.  This is all just a nasty hack to avoid calling
2402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// directly from m_syswrap to m_main at exit, since that would cause
2403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// m_main to become part of a module cycle, which is silly.
2404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid (* VG_(address_of_m_main_shutdown_actions_NORETURN) )
2405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       (ThreadId,VgSchedReturnCode)
2406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   = NULL;
2407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
2409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
2410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
2411