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
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2000-2011 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)
71b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
72b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   On s390x the svc instruction is used for system calls. The system call
73b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   number is encoded in the instruction (8 bit immediate field). Since Linux
74b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   2.6 it is also allowed to use svc 0 with the system call number in r1.
75b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   This was introduced for system calls >255, but works for all. It is
76b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   also possible to see the svc 0 together with an EXecute instruction, that
77b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   fills in the immediate field.
78b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   s390x r1/SVC r2   r3   r4   r5   r6   r7   n/a  n/a  r2        (== ARG1)
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DARWIN:
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x86    eax +4   +8   +12  +16  +20  +24  +28  +32  edx:eax, eflags.c
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amd64  rax rdi  rsi  rdx  rcx  r8   r9   +8   +16  rdx:rax, rflags.c
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   For x86-darwin, "+N" denotes "in memory at N(%esp)"; ditto
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amd64-darwin.  Apparently 0(%esp) is some kind of return address
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (perhaps for syscalls done with "sysenter"?)  I don't think it is
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   relevant for syscalls done with "int $0x80/1/2".
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the top level of the system-call handler module.  All
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   system calls are channelled through here, doing two things:
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * notify the tool of the events (mem/reg reads, writes) happening
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * perform the syscall, usually by passing it along to the kernel
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     unmodified.
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   A magical piece of assembly code, do_syscall_for_client_WRK, in
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscall-$PLATFORM.S does the tricky bit of passing a syscall to the
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   kernel, whilst having the simulator retain control.
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The main function is VG_(client_syscall).  The simulation calls it
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   whenever a client thread wants to do a syscall.  The following is a
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sketch of what it does.
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * Ensures the root thread's stack is suitably mapped.  Tedious and
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     arcane.  See big big comment in VG_(client_syscall).
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * First, it rounds up the syscall number and args (which is a
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     platform dependent activity) and puts them in a struct ("args")
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     and also a copy in "orig_args".
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     The pre/post wrappers refer to these structs and so no longer
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     need magic macros to access any specific registers.  This struct
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     is stored in thread-specific storage.
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * The pre-wrapper is called, passing it a pointer to struct
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     "args".
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * The pre-wrapper examines the args and pokes the tool
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     appropriately.  It may modify the args; this is why "orig_args"
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     is also stored.
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     The pre-wrapper may choose to 'do' the syscall itself, and
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     concludes one of three outcomes:
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       Success(N)    -- syscall is already complete, with success;
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        result is N
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       Fail(N)       -- syscall is already complete, with failure;
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        error code is N
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       HandToKernel  -- (the usual case): this needs to be given to
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        the kernel to be done, using the values in
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        the possibly-modified "args" struct.
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     In addition, the pre-wrapper may set some flags:
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       MayBlock   -- only applicable when outcome==HandToKernel
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       PostOnFail -- only applicable when outcome==HandToKernel or Fail
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * If the pre-outcome is HandToKernel, the syscall is duly handed
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     off to the kernel (perhaps involving some thread switchery, but
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     that's not important).  This reduces the possible set of outcomes
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     to either Success(N) or Fail(N).
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * The outcome (Success(N) or Fail(N)) is written back to the guest
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     register(s).  This is platform specific:
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     x86:    Success(N) ==>  eax = N
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Fail(N)    ==>  eax = -N
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     ditto amd64
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     ppc32:  Success(N) ==>  r3 = N, CR0.SO = 0
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Fail(N) ==>     r3 = N, CR0.SO = 1
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Darwin:
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     x86:    Success(N) ==>  edx:eax = N, cc = 0
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Fail(N)    ==>  edx:eax = N, cc = 1
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
168b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     s390x:  Success(N) ==>  r2 = N
169b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             Fail(N)    ==>  r2 = -N
170b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * The post wrapper is called if:
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     - it exists, and
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     - outcome==Success or (outcome==Fail and PostOnFail is set)
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     The post wrapper is passed the adulterated syscall args (struct
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     "args"), and the syscall outcome (viz, Success(N) or Fail(N)).
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   There are several other complications, primarily to do with
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscalls getting interrupted, explained in comments in the code.
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* CAVEATS for writing wrappers.  It is important to follow these!
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The macros defined in priv_types_n_macros.h are designed to help
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   decouple the wrapper logic from the actual representation of
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscall args/results, since these wrappers are designed to work on
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   multiple platforms.
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Sometimes a PRE wrapper will complete the syscall itself, without
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   handing it to the kernel.  It will use one of SET_STATUS_Success,
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SET_STATUS_Failure or SET_STATUS_from_SysRes to set the return
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value.  It is critical to appreciate that use of the macro does not
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   immediately cause the underlying guest state to be updated -- that
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is done by the driver logic in this file, when the wrapper returns.
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   As a result, PRE wrappers of the following form will malfunction:
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRE(fooble)
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ... do stuff ...
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SET_STATUS_Somehow(...)
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // do something that assumes guest state is up to date
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   In particular, direct or indirect calls to VG_(poll_signals) after
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setting STATUS can cause the guest state to be read (in order to
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   build signal frames).  Do not do this.  If you want a signal poll
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   after the syscall goes through, do "*flags |= SfPollAfter" and the
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   driver logic will do it for you.
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   -----------
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Another critical requirement following introduction of new address
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   space manager (JRS, 20050923):
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   In a situation where the mappedness of memory has changed, aspacem
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   should be notified BEFORE the tool.  Hence the following is
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   correct:
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool d = VG_(am_notify_munmap)(s->start, s->end+1 - s->start);
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( die_mem_munmap, s->start, s->end+1 - s->start );
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d)
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(discard_translations)(s->start, s->end+1 - s->start);
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   whilst this is wrong:
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TRACK( die_mem_munmap, s->start, s->end+1 - s->start );
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool d = VG_(am_notify_munmap)(s->start, s->end+1 - s->start);
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d)
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(discard_translations)(s->start, s->end+1 - s->start);
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The reason is that the tool may itself ask aspacem for more shadow
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memory as a result of the VG_TRACK call.  In such a situation it is
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   critical that aspacem's segment array is up to date -- hence the
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   need to notify aspacem first.
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   -----------
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Also .. take care to call VG_(discard_translations) whenever
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   memory with execute permissions is unmapped.
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Do potentially blocking syscall for the client, and mess with
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   signal masks at the same time.
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Perform a syscall on behalf of a client thread, using a specific
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   signal mask.  On completion, the signal mask is set to restore_mask
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (which presumably blocks almost everything).  If a signal happens
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   during the syscall, the handler should call
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(fixup_guest_state_after_syscall_interrupted) to adjust the
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread's context to do the right thing.
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The _WRK function is handwritten assembly, implemented per-platform
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in coregrind/m_syswrap/syscall-$PLAT.S.  It has some very magic
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   properties.  See comments at the top of
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(fixup_guest_state_after_syscall_interrupted) below for details.
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This function (these functions) are required to return zero in case
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of success (even if the syscall itself failed), and nonzero if the
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sigprocmask-swizzling calls failed.  We don't actually care about
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the failure values from sigprocmask, although most of the assembly
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   implementations do attempt to return that, using the convention
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0 for success, or 0x8000 | error-code for failure.
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_linux)
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownextern
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUWord ML_(do_syscall_for_client_WRK)( Word syscallno,
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      void* guest_state,
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      const vki_sigset_t *syscall_mask,
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      const vki_sigset_t *restore_mask,
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      Word sigsetSzB );
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGO_darwin)
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownextern
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUWord ML_(do_syscall_for_client_unix_WRK)( Word syscallno,
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           void* guest_state,
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *syscall_mask,
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *restore_mask,
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Word sigsetSzB ); /* unused */
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownextern
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUWord ML_(do_syscall_for_client_mach_WRK)( Word syscallno,
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           void* guest_state,
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *syscall_mask,
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *restore_mask,
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Word sigsetSzB ); /* unused */
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownextern
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUWord ML_(do_syscall_for_client_mdep_WRK)( Word syscallno,
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           void* guest_state,
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *syscall_mask,
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           const vki_sigset_t *restore_mask,
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           Word sigsetSzB ); /* unused */
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "Unknown OS"
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid do_syscall_for_client ( Int syscallno,
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             ThreadState* tst,
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             const vki_sigset_t* syscall_mask )
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vki_sigset_t saved;
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord err;
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   err = ML_(do_syscall_for_client_WRK)(
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            syscallno, &tst->arch.vex,
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            syscall_mask, &saved, sizeof(vki_sigset_t)
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (VG_DARWIN_SYSNO_CLASS(syscallno)) {
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_UNIX:
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         err = ML_(do_syscall_for_client_unix_WRK)(
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  VG_DARWIN_SYSNO_FOR_KERNEL(syscallno), &tst->arch.vex,
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  syscall_mask, &saved, 0/*unused:sigsetSzB*/
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MACH:
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         err = ML_(do_syscall_for_client_mach_WRK)(
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  VG_DARWIN_SYSNO_FOR_KERNEL(syscallno), &tst->arch.vex,
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  syscall_mask, &saved, 0/*unused:sigsetSzB*/
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MDEP:
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         err = ML_(do_syscall_for_client_mdep_WRK)(
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  VG_DARWIN_SYSNO_FOR_KERNEL(syscallno), &tst->arch.vex,
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  syscall_mask, &saved, 0/*unused:sigsetSzB*/
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert2(
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      err == 0,
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "ML_(do_syscall_for_client_WRK): sigprocmask error %d",
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (Int)(err & 0xFFF)
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Impedance matchers and misc helpers
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool eq_SyscallArgs ( SyscallArgs* a1, SyscallArgs* a2 )
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return a1->sysno == a2->sysno
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg1 == a2->arg1
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg2 == a2->arg2
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg3 == a2->arg3
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg4 == a2->arg4
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg5 == a2->arg5
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg6 == a2->arg6
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg7 == a2->arg7
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && a1->arg8 == a2->arg8;
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool eq_SyscallStatus ( SyscallStatus* s1, SyscallStatus* s2 )
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* was: return s1->what == s2->what && sr_EQ( s1->sres, s2->sres ); */
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (s1->what == s2->what && sr_EQ( s1->sres, s2->sres ))
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return True;
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_darwin)
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Darwin-specific debugging guff */
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(s1->what == s2->what);
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("eq_SyscallStatus:\n");
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("  {%lu %lu %u}\n", s1->sres._wLO, s1->sres._wHI, s1->sres._mode);
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(printf)("  {%lu %lu %u}\n", s2->sres._wLO, s2->sres._wHI, s2->sres._mode);
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Convert between SysRes and SyscallStatus, to the extent possible. */
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSyscallStatus convert_SysRes_to_SyscallStatus ( SysRes res )
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallStatus status;
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   status.what = SsComplete;
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   status.sres = res;
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return status;
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Impedance matchers.  These convert syscall arg or result data from
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the platform-specific in-guest-state format to the canonical
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   formats, and back. */
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid getSyscallArgsFromGuestState ( /*OUT*/SyscallArgs*       canonical,
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    /*IN*/ VexGuestArchState* gst_vanilla,
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    /*IN*/ UInt trc )
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_x86_linux)
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_EAX;
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg1  = gst->guest_EBX;
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg2  = gst->guest_ECX;
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg3  = gst->guest_EDX;
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg4  = gst->guest_ESI;
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg5  = gst->guest_EDI;
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg6  = gst->guest_EBP;
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg7  = 0;
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg8  = 0;
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_linux)
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_RAX;
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg1  = gst->guest_RDI;
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg2  = gst->guest_RSI;
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg3  = gst->guest_RDX;
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg4  = gst->guest_R10;
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg5  = gst->guest_R8;
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg6  = gst->guest_R9;
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg7  = 0;
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg8  = 0;
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc32_linux)
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_GPR0;
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg1  = gst->guest_GPR3;
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg2  = gst->guest_GPR4;
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg3  = gst->guest_GPR5;
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg4  = gst->guest_GPR6;
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg5  = gst->guest_GPR7;
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg6  = gst->guest_GPR8;
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg7  = 0;
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg8  = 0;
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc64_linux)
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_GPR0;
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg1  = gst->guest_GPR3;
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg2  = gst->guest_GPR4;
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg3  = gst->guest_GPR5;
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg4  = gst->guest_GPR6;
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg5  = gst->guest_GPR7;
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg6  = gst->guest_GPR8;
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg7  = 0;
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg8  = 0;
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_arm_linux)
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_R7;
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg1  = gst->guest_R0;
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg2  = gst->guest_R1;
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg3  = gst->guest_R2;
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg4  = gst->guest_R3;
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg5  = gst->guest_R4;
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg6  = gst->guest_R5;
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg7  = 0;
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->arg8  = 0;
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_x86_darwin)
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord *stack = (UWord *)gst->guest_ESP;
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme hope syscalls aren't called with really shallow stacks...
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_EAX;
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (canonical->sysno != 0) {
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // stack[0] is return address
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg1  = stack[1];
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg2  = stack[2];
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg3  = stack[3];
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg4  = stack[4];
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg5  = stack[5];
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg6  = stack[6];
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg7  = stack[7];
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg8  = stack[8];
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme hack handle syscall()
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme what about __syscall() ?
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // stack[0] is return address
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // DDD: the tool can't see that the params have been shifted!  Can
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //      lead to incorrect checking, I think, because the PRRAn/PSARn
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //      macros will mention the pre-shifted args.
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->sysno = stack[1];
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(canonical->sysno != 0);
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg1  = stack[2];
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg2  = stack[3];
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg3  = stack[4];
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg4  = stack[5];
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg5  = stack[6];
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg6  = stack[7];
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg7  = stack[8];
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg8  = stack[9];
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      PRINT("SYSCALL[%d,?](%s) syscall(%s, ...); please stand by...\n",
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(getpid)(), /*tid,*/
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_SYSNUM_STRING(0), VG_SYSNUM_STRING(canonical->sysno));
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Here we determine what kind of syscall it was by looking at the
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // interrupt kind, and then encode the syscall number using the 64-bit
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // encoding for Valgrind's internal use.
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // DDD: Would it be better to stash the JMP kind into the Darwin
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // thread state rather than passing in the trc?
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (trc) {
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VEX_TRC_JMP_SYS_INT128:
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // int $0x80 = Unix, 64-bit result
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(canonical->sysno >= 0);
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(canonical->sysno);
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VEX_TRC_JMP_SYS_SYSENTER:
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // syscall = Unix, 32-bit result
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // OR        Mach, 32-bit result
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (canonical->sysno >= 0) {
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // GrP fixme hack:  0xffff == I386_SYSCALL_NUMBER_MASK
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(canonical->sysno
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                             & 0xffff);
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MACH(-canonical->sysno);
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VEX_TRC_JMP_SYS_INT129:
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // int $0x81 = Mach, 32-bit result
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(canonical->sysno < 0);
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MACH(-canonical->sysno);
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VEX_TRC_JMP_SYS_INT130:
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // int $0x82 = mdep, 32-bit result
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(canonical->sysno >= 0);
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(canonical->sysno);
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0);
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_darwin)
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord *stack = (UWord *)gst->guest_RSP;
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(trc == VEX_TRC_JMP_SYS_SYSCALL);
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme hope syscalls aren't called with really shallow stacks...
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sysno = gst->guest_RAX;
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (canonical->sysno != __NR_syscall) {
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // stack[0] is return address
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg1  = gst->guest_RDI;
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg2  = gst->guest_RSI;
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg3  = gst->guest_RDX;
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg4  = gst->guest_R10;  // not rcx with syscall insn
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg5  = gst->guest_R8;
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg6  = gst->guest_R9;
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg7  = stack[1];
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg8  = stack[2];
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme hack handle syscall()
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // GrP fixme what about __syscall() ?
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // stack[0] is return address
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // DDD: the tool can't see that the params have been shifted!  Can
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //      lead to incorrect checking, I think, because the PRRAn/PSARn
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //      macros will mention the pre-shifted args.
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(gst->guest_RDI);
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(canonical->sysno != __NR_syscall);
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg1  = gst->guest_RSI;
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg2  = gst->guest_RDX;
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg3  = gst->guest_R10;  // not rcx with syscall insn
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg4  = gst->guest_R8;
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg5  = gst->guest_R9;
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg6  = stack[1];
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg7  = stack[2];
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical->arg8  = stack[3];
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      PRINT("SYSCALL[%d,?](%s) syscall(%s, ...); please stand by...\n",
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(getpid)(), /*tid,*/
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_SYSNUM_STRING(0), VG_SYSNUM_STRING(canonical->sysno));
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // no canonical->sysno adjustment needed
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
584b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined(VGP_s390x_linux)
585b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VexGuestS390XState* gst = (VexGuestS390XState*)gst_vanilla;
586b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->sysno = gst->guest_SYSNO;
587b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg1  = gst->guest_r2;
588b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg2  = gst->guest_r3;
589b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg3  = gst->guest_r4;
590b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg4  = gst->guest_r5;
591b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg5  = gst->guest_r6;
592b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg6  = gst->guest_r7;
593b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg7  = 0;
594b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->arg8  = 0;
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "getSyscallArgsFromGuestState: unknown arch"
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid putSyscallArgsIntoGuestState ( /*IN*/ SyscallArgs*       canonical,
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    /*OUT*/VexGuestArchState* gst_vanilla )
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_x86_linux)
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EAX = canonical->sysno;
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EBX = canonical->arg1;
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_ECX = canonical->arg2;
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EDX = canonical->arg3;
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_ESI = canonical->arg4;
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EDI = canonical->arg5;
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EBP = canonical->arg6;
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_linux)
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RAX = canonical->sysno;
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RDI = canonical->arg1;
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RSI = canonical->arg2;
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RDX = canonical->arg3;
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R10 = canonical->arg4;
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R8  = canonical->arg5;
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R9  = canonical->arg6;
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc32_linux)
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR0 = canonical->sysno;
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR3 = canonical->arg1;
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR4 = canonical->arg2;
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR5 = canonical->arg3;
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR6 = canonical->arg4;
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR7 = canonical->arg5;
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR8 = canonical->arg6;
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc64_linux)
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR0 = canonical->sysno;
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR3 = canonical->arg1;
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR4 = canonical->arg2;
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR5 = canonical->arg3;
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR6 = canonical->arg4;
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR7 = canonical->arg5;
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_GPR8 = canonical->arg6;
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_arm_linux)
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R7 = canonical->sysno;
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R0 = canonical->arg1;
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R1 = canonical->arg2;
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R2 = canonical->arg3;
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R3 = canonical->arg4;
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R4 = canonical->arg5;
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R5 = canonical->arg6;
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_x86_darwin)
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord *stack = (UWord *)gst->guest_ESP;
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_EAX = VG_DARWIN_SYSNO_FOR_KERNEL(canonical->sysno);
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme? gst->guest_TEMP_EFLAG_C = 0;
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // stack[0] is return address
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[1] = canonical->arg1;
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[2] = canonical->arg2;
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[3] = canonical->arg3;
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[4] = canonical->arg4;
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[5] = canonical->arg5;
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[6] = canonical->arg6;
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[7] = canonical->arg7;
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[8] = canonical->arg8;
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_darwin)
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UWord *stack = (UWord *)gst->guest_RSP;
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RAX = VG_DARWIN_SYSNO_FOR_KERNEL(canonical->sysno);
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // GrP fixme? gst->guest_TEMP_EFLAG_C = 0;
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // stack[0] is return address
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RDI = canonical->arg1;
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RSI = canonical->arg2;
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RDX = canonical->arg3;
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_RCX = canonical->arg4;
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R8  = canonical->arg5;
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   gst->guest_R9  = canonical->arg6;
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[1]       = canonical->arg7;
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stack[2]       = canonical->arg8;
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
688b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined(VGP_s390x_linux)
689b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VexGuestS390XState* gst = (VexGuestS390XState*)gst_vanilla;
690b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_SYSNO  = canonical->sysno;
691b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r2     = canonical->arg1;
692b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r3     = canonical->arg2;
693b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r4     = canonical->arg3;
694b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r5     = canonical->arg4;
695b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r6     = canonical->arg5;
696b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   gst->guest_r7     = canonical->arg6;
697b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "putSyscallArgsIntoGuestState: unknown arch"
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid getSyscallStatusFromGuestState ( /*OUT*/SyscallStatus*     canonical,
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      /*IN*/ VexGuestArchState* gst_vanilla )
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux)
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_x86_linux)( gst->guest_EAX );
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux)
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_amd64_linux)( gst->guest_RAX );
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc32_linux)
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC32State* gst   = (VexGuestPPC32State*)gst_vanilla;
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt                cr    = LibVEX_GuestPPC32_get_CR( gst );
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt                cr0so = (cr >> 28) & 1;
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_ppc32_linux)( gst->guest_GPR3, cr0so );
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc64_linux)
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC64State* gst   = (VexGuestPPC64State*)gst_vanilla;
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt                cr    = LibVEX_GuestPPC64_get_CR( gst );
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt                cr0so = (cr >> 28) & 1;
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_ppc64_linux)( gst->guest_GPR3, cr0so );
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_arm_linux)
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_arm_linux)( gst->guest_R0 );
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_x86_darwin)
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt carry = 1 & LibVEX_GuestX86_get_eflags(gst);
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt err = 0;
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt wLO = 0;
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt wHI = 0;
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gst->guest_SC_CLASS) {
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_UNIX:
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // int $0x80 = Unix, 64-bit result
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         err = carry;
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_EAX;
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wHI = gst->guest_EDX;
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MACH:
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // int $0x81 = Mach, 32-bit result
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_EAX;
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MDEP:
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // int $0x82 = mdep, 32-bit result
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_EAX;
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_x86_darwin)(
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        gst->guest_SC_CLASS, err ? True : False,
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        wHI, wLO
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_darwin)
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong carry = 1 & LibVEX_GuestAMD64_get_rflags(gst);
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong err = 0;
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong wLO = 0;
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong wHI = 0;
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gst->guest_SC_CLASS) {
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_UNIX:
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // syscall = Unix, 128-bit result
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         err = carry;
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_RAX;
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wHI = gst->guest_RDX;
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MACH:
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // syscall = Mach, 64-bit result
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_RAX;
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case VG_DARWIN_SYSCALL_CLASS_MDEP:
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // syscall = mdep, 64-bit result
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         wLO = gst->guest_RAX;
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->sres = VG_(mk_SysRes_amd64_darwin)(
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        gst->guest_SC_CLASS, err ? True : False,
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        wHI, wLO
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   canonical->what = SsComplete;
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
800b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGP_s390x_linux)
801b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VexGuestS390XState* gst   = (VexGuestS390XState*)gst_vanilla;
802b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->sres = VG_(mk_SysRes_s390x_linux)( gst->guest_r2 );
803b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   canonical->what = SsComplete;
804b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "getSyscallStatusFromGuestState: unknown arch"
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid putSyscallStatusIntoGuestState ( /*IN*/ ThreadId tid,
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      /*IN*/ SyscallStatus*     canonical,
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      /*OUT*/VexGuestArchState* gst_vanilla )
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGP_x86_linux)
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(canonical->sres)) {
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This isn't exactly right, in that really a Failure with res
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         not in the range 1 .. 4095 is unrepresentable in the
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Linux-x86 scheme.  Oh well. */
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_EAX = - (Int)sr_Err(canonical->sres);
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_EAX = sr_Res(canonical->sres);
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_x86_EAX, sizeof(UWord) );
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_amd64_linux)
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(canonical->sres)) {
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This isn't exactly right, in that really a Failure with res
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         not in the range 1 .. 4095 is unrepresentable in the
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Linux-amd64 scheme.  Oh well. */
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_RAX = - (Long)sr_Err(canonical->sres);
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_RAX = sr_Res(canonical->sres);
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_amd64_RAX, sizeof(UWord) );
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc32_linux)
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt old_cr = LibVEX_GuestPPC32_get_CR(gst);
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(canonical->sres)) {
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set CR0.SO */
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LibVEX_GuestPPC32_put_CR( old_cr | (1<<28), gst );
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_GPR3 = sr_Err(canonical->sres);
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* clear CR0.SO */
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LibVEX_GuestPPC32_put_CR( old_cr & ~(1<<28), gst );
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_GPR3 = sr_Res(canonical->sres);
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_ppc32_GPR3, sizeof(UWord) );
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_ppc32_CR0_0, sizeof(UChar) );
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_ppc64_linux)
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt old_cr = LibVEX_GuestPPC64_get_CR(gst);
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(canonical->sres)) {
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* set CR0.SO */
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LibVEX_GuestPPC64_put_CR( old_cr | (1<<28), gst );
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_GPR3 = sr_Err(canonical->sres);
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* clear CR0.SO */
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      LibVEX_GuestPPC64_put_CR( old_cr & ~(1<<28), gst );
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_GPR3 = sr_Res(canonical->sres);
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_ppc64_GPR3, sizeof(UWord) );
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_ppc64_CR0_0, sizeof(UChar) );
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGP_arm_linux)
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla;
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sr_isError(canonical->sres)) {
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This isn't exactly right, in that really a Failure with res
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         not in the range 1 .. 4095 is unrepresentable in the
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Linux-arm scheme.  Oh well. */
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_R0 = - (Int)sr_Err(canonical->sres);
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      gst->guest_R0 = sr_Res(canonical->sres);
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             OFFSET_arm_R0, sizeof(UWord) );
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_x86_darwin)
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres = canonical->sres;
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Unfortunately here we have to break abstraction and look
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      directly inside 'res', in order to decide what to do. */
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sres._mode) {
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_MACH: // int $0x81 = Mach, 32-bit result
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_MDEP: // int $0x82 = mdep, 32-bit result
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_EAX = sres._wLO;
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_x86_EAX, sizeof(UInt) );
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_UNIX_OK:  // int $0x80 = Unix, 64-bit result
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_UNIX_ERR: // int $0x80 = Unix, 64-bit error
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_EAX = sres._wLO;
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_x86_EAX, sizeof(UInt) );
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_EDX = sres._wHI;
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_x86_EDX, sizeof(UInt) );
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         LibVEX_GuestX86_put_eflag_c( sres._mode==SysRes_UNIX_ERR ? 1 : 0,
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      gst );
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // GrP fixme sets defined for entire eflags, not just bit c
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // DDD: this breaks exp-ptrcheck.
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   offsetof(VexGuestX86State, guest_CC_DEP1), sizeof(UInt) );
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_darwin)
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SysRes sres = canonical->sres;
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(canonical->what == SsComplete);
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Unfortunately here we have to break abstraction and look
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      directly inside 'res', in order to decide what to do. */
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sres._mode) {
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_MACH: // syscall = Mach, 64-bit result
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_MDEP: // syscall = mdep, 64-bit result
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_RAX = sres._wLO;
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_amd64_RAX, sizeof(ULong) );
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_UNIX_OK:  // syscall = Unix, 128-bit result
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case SysRes_UNIX_ERR: // syscall = Unix, 128-bit error
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_RAX = sres._wLO;
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_amd64_RAX, sizeof(ULong) );
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gst->guest_RDX = sres._wHI;
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   OFFSET_amd64_RDX, sizeof(ULong) );
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         LibVEX_GuestAMD64_put_rflag_c( sres._mode==SysRes_UNIX_ERR ? 1 : 0,
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        gst );
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // GrP fixme sets defined for entire rflags, not just bit c
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         // DDD: this breaks exp-ptrcheck.
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   offsetof(VexGuestAMD64State, guest_CC_DEP1), sizeof(ULong) );
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(0);
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
959b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  elif defined(VGP_s390x_linux)
960b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VexGuestS390XState* gst = (VexGuestS390XState*)gst_vanilla;
961b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vg_assert(canonical->what == SsComplete);
962b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (sr_isError(canonical->sres)) {
963b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      gst->guest_r2 = - (Long)sr_Err(canonical->sres);
964b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
965b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      gst->guest_r2 = sr_Res(canonical->sres);
966b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
967b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "putSyscallStatusIntoGuestState: unknown arch"
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Tell me the offsets in the guest state of the syscall params, so
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that the scalar argument checkers don't have to have this info
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   hardwired. */
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid getSyscallArgLayout ( /*OUT*/SyscallArgLayout* layout )
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_x86_linux)
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_x86_EAX;
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_x86_EBX;
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_x86_ECX;
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_x86_EDX;
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_x86_ESI;
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_x86_EDI;
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_x86_EBP;
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg7  = -1; /* impossible value */
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg8  = -1; /* impossible value */
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_linux)
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_amd64_RAX;
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_amd64_RDI;
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_amd64_RSI;
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_amd64_RDX;
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_amd64_R10;
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_amd64_R8;
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_amd64_R9;
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg7  = -1; /* impossible value */
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg8  = -1; /* impossible value */
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc32_linux)
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_ppc32_GPR0;
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_ppc32_GPR3;
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_ppc32_GPR4;
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_ppc32_GPR5;
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_ppc32_GPR6;
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_ppc32_GPR7;
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_ppc32_GPR8;
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg7  = -1; /* impossible value */
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg8  = -1; /* impossible value */
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc64_linux)
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_ppc64_GPR0;
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_ppc64_GPR3;
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_ppc64_GPR4;
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_ppc64_GPR5;
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_ppc64_GPR6;
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_ppc64_GPR7;
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_ppc64_GPR8;
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg7  = -1; /* impossible value */
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg8  = -1; /* impossible value */
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_arm_linux)
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_arm_R7;
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_arm_R0;
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_arm_R1;
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_arm_R2;
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_arm_R3;
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_arm_R4;
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_arm_R5;
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg7  = -1; /* impossible value */
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->uu_arg8  = -1; /* impossible value */
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_x86_darwin)
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_x86_EAX;
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // syscall parameters are on stack in C convention
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg1   = sizeof(UWord) * 1;
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg2   = sizeof(UWord) * 2;
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg3   = sizeof(UWord) * 3;
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg4   = sizeof(UWord) * 4;
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg5   = sizeof(UWord) * 5;
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg6   = sizeof(UWord) * 6;
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg7   = sizeof(UWord) * 7;
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg8   = sizeof(UWord) * 8;
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_darwin)
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_sysno  = OFFSET_amd64_RAX;
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg1   = OFFSET_amd64_RDI;
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg2   = OFFSET_amd64_RSI;
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg3   = OFFSET_amd64_RDX;
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg4   = OFFSET_amd64_RCX;
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg5   = OFFSET_amd64_R8;
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->o_arg6   = OFFSET_amd64_R9;
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg7   = sizeof(UWord) * 1;
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   layout->s_arg8   = sizeof(UWord) * 2;
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1059b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined(VGP_s390x_linux)
1060b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_sysno  = OFFSET_s390x_SYSNO;
1061b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg1   = OFFSET_s390x_r2;
1062b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg2   = OFFSET_s390x_r3;
1063b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg3   = OFFSET_s390x_r4;
1064b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg4   = OFFSET_s390x_r5;
1065b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg5   = OFFSET_s390x_r6;
1066b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->o_arg6   = OFFSET_s390x_r7;
1067b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->uu_arg7  = -1; /* impossible value */
1068b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   layout->uu_arg8  = -1; /* impossible value */
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "getSyscallLayout: unknown arch"
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The main driver logic
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Finding the handlers for a given syscall, or faking up one
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   when no handler is found. */
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid bad_before ( ThreadId              tid,
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  SyscallArgLayout*     layout,
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*MOD*/SyscallArgs*   args,
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*OUT*/SyscallStatus* status,
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*OUT*/UWord*         flags )
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dmsg)("WARNING: unhandled syscall: %s\n",
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_SYSNUM_STRING_EXTRA(args->sysno));
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_verbosity) > 1) {
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dmsg)("You may be able to write your own handler.\n");
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dmsg)("Read the file README_MISSING_SYSCALL_OR_IOCTL.\n");
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dmsg)("Nevertheless we consider this a bug.  Please report\n");
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(dmsg)("it at http://valgrind.org/support/bug_reports.html.\n");
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SET_STATUS_Failure(VKI_ENOSYS);
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic SyscallTableEntry bad_sys =
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   { bad_before, NULL };
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic const SyscallTableEntry* get_syscall_entry ( Int syscallno )
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const SyscallTableEntry* sys = NULL;
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sys = ML_(get_linux_syscall_entry)( syscallno );
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int idx = VG_DARWIN_SYSNO_INDEX(syscallno);
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (VG_DARWIN_SYSNO_CLASS(syscallno)) {
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VG_DARWIN_SYSCALL_CLASS_UNIX:
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (idx >= 0 && idx < ML_(syscall_table_size) &&
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ML_(syscall_table)[idx].before != NULL)
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sys = &ML_(syscall_table)[idx];
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VG_DARWIN_SYSCALL_CLASS_MACH:
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (idx >= 0 && idx < ML_(mach_trap_table_size) &&
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ML_(mach_trap_table)[idx].before != NULL)
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sys = &ML_(mach_trap_table)[idx];
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case VG_DARWIN_SYSCALL_CLASS_MDEP:
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (idx >= 0 && idx < ML_(mdep_trap_table_size) &&
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ML_(mdep_trap_table)[idx].before != NULL)
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sys = &ML_(mdep_trap_table)[idx];
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0);
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error Unknown OS
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sys == NULL  ? &bad_sys  : sys;
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add and remove signals from mask so that we end up telling the
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   kernel the state we actually want rather than what the client
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   wants. */
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void sanitize_client_sigmask(vki_sigset_t *mask)
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(mask, VKI_SIGKILL);
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(mask, VKI_SIGSTOP);
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(sigdelset)(mask, VG_SIGVGKILL); /* never block */
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct {
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SyscallArgs   orig_args;
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SyscallArgs   args;
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SyscallStatus status;
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UWord         flags;
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallInfo;
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownSyscallInfo syscallInfo[VG_N_THREADS];
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The scheduler needs to be able to zero out these records after a
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fork, hence this is exported from m_syswrap. */
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(clear_syscallInfo) ( Int tid )
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 0 && tid < VG_N_THREADS);
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)( & syscallInfo[tid], 0, sizeof( syscallInfo[tid] ));
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscallInfo[tid].status.what = SsIdle;
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void ensure_initialised ( void )
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static Bool init_done = False;
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (init_done)
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_done = True;
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < VG_N_THREADS; i++) {
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(clear_syscallInfo)( i );
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- This is the main function of this file. --- */
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(client_syscall) ( ThreadId tid, UInt trc )
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word                     sysno;
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState*             tst;
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const SyscallTableEntry* ent;
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallArgLayout         layout;
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallInfo*             sci;
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ensure_initialised();
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 1 && tid < VG_N_THREADS);
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst = VG_(get_ThreadState)(tid);
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* BEGIN ensure root thread's stack is suitably mapped */
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* In some rare circumstances, we may do the syscall without the
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      bottom page of the stack being mapped, because the stack pointer
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      was moved down just a few instructions before the syscall
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      instruction, and there have been no memory references since
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      then, that would cause a call to VG_(extend_stack) to have
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      happened.
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      In native execution that's OK: the kernel automagically extends
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the stack's mapped area down to cover the stack pointer (or sp -
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      redzone, really).  In simulated normal execution that's OK too,
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      since any signals we get from accessing below the mapped area of
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the (guest's) stack lead us to VG_(extend_stack), where we
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      simulate the kernel's stack extension logic.  But that leaves
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the problem of entering a syscall with the SP unmapped.  Because
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the kernel doesn't know that the segment immediately above SP is
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      supposed to be a grow-down segment, it causes the syscall to
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fail, and thereby causes a divergence between native behaviour
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (syscall succeeds) and simulated behaviour (syscall fails).
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      This is quite a rare failure mode.  It has only been seen
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      affecting calls to sys_readlink on amd64-linux, and even then it
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      requires a certain code sequence around the syscall to trigger
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      it.  Here is one:
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      extern int my_readlink ( const char* path );
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      asm(
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ".text\n"
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ".globl my_readlink\n"
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "my_readlink:\n"
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tsubq    $0x1008,%rsp\n"
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tmovq    %rdi,%rdi\n"              // path is in rdi
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tmovq    %rsp,%rsi\n"              // &buf[0] -> rsi
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tmovl    $0x1000,%edx\n"           // sizeof(buf) in rdx
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tmovl    $"__NR_READLINK",%eax\n"  // syscall number
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tsyscall\n"
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\taddq    $0x1008,%rsp\n"
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      "\tret\n"
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ".previous\n"
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      For more details, see bug #156404
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (https://bugs.kde.org/show_bug.cgi?id=156404).
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The fix is actually very simple.  We simply need to call
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(extend_stack) for this thread, handing it the lowest
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      possible valid address for stack (sp - redzone), to ensure the
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pages all the way down to that address, are mapped.  Because
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      this is a potentially expensive and frequent operation, we
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      filter in two ways:
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      First, only the main thread (tid=1) has a growdown stack.  So
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ignore all others.  It is conceivable, although highly unlikely,
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that the main thread exits, and later another thread is
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allocated tid=1, but that's harmless, I believe;
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(extend_stack) will do nothing when applied to a non-root
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thread.
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Secondly, first call VG_(am_find_nsegment) directly, to see if
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the page holding (sp - redzone) is mapped correctly.  If so, do
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      nothing.  This is almost always the case.  VG_(extend_stack)
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      calls VG_(am_find_nsegment) twice, so this optimisation -- and
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that's all it is -- more or less halves the number of calls to
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(am_find_nsegment) required.
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      TODO: the test "seg->kind == SkAnonC" is really inadequate,
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      because although it tests whether the segment is mapped
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      _somehow_, it doesn't check that it has the right permissions
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (r,w, maybe x) ?  We could test that here, but it will also be
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      necessary to fix the corresponding test in VG_(extend_stack).
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      All this guff is of course Linux-specific.  Hence the ifdef.
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (tid == 1/*ROOT THREAD*/) {
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr     stackMin   = VG_(get_SP)(tid) - VG_STACK_REDZONE_SZB;
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      NSegment const* seg = VG_(am_find_nsegment)(stackMin);
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (seg && seg->kind == SkAnonC) {
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* stackMin is already mapped.  Nothing to do. */
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (void)VG_(extend_stack)( stackMin,
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  tst->client_stack_szB );
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* END ensure root thread's stack is suitably mapped */
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First off, get the syscall args and number.  This is a
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      platform-dependent action. */
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci = & syscallInfo[tid];
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what == SsIdle);
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   getSyscallArgsFromGuestState( &sci->orig_args, &tst->arch.vex, trc );
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy .orig_args to .args.  The pre-handler may modify .args, but
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      we want to keep the originals too, just in case. */
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->args = sci->orig_args;
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Save the syscall number in the thread state in case the syscall
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is interrupted by a signal. */
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sysno = sci->orig_args.sysno;
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1308b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* It's sometimes useful, as a crude debugging hack, to get a
1309b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      stack trace at each (or selected) syscalls. */
1310b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (0 && sysno == __NR_ioctl) {
1311b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)("\nioctl:\n");
1312b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(get_and_pp_StackTrace)(tid, 10);
1313b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)("\n");
1314b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1315b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_darwin)
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Record syscall class.  But why?  Because the syscall might be
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interrupted by a signal, and in the signal handler (which will
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      be m_signals.async_signalhandler) we will need to build a SysRes
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reflecting the syscall return result.  In order to do that we
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      need to know the syscall class.  Hence stash it in the guest
1322b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      state of this thread.  This madness is not needed on Linux
1323b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      because it only has a single syscall return convention and so
1324b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      there is no ambiguity involved in converting the post-signal
1325b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      machine state into a SysRes. */
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst->arch.vex.guest_SC_CLASS = VG_DARWIN_SYSNO_CLASS(sysno);
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The default what-to-do-next thing is hand the syscall to the
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      kernel, so we pre-set that here.  Set .sres to something
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      harmless looking (is irrelevant because .what is not
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SsComplete.) */
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status.what = SsHandToKernel;
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status.sres = VG_(mk_SysRes_Error)(0);
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->flags       = 0;
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fetch the syscall's handlers.  If no handlers exist for this
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      syscall, we are given dummy handlers which force an immediate
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return with ENOSYS. */
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ent = get_syscall_entry(sysno);
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fetch the layout information, which tells us where in the guest
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      state the syscall args reside.  This is a platform-dependent
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      action.  This info is needed so that the scalar syscall argument
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      checks (PRE_REG_READ calls) know which bits of the guest state
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      they need to inspect. */
1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   getSyscallArgLayout( &layout );
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure the tmp signal mask matches the real signal mask;
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sigsuspend may change this. */
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(iseqsigset)(&tst->sig_mask, &tst->tmp_sig_mask));
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Right, we're finally ready to Party.  Call the pre-handler and
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      see what we get back.  At this point:
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        sci->status.what  is Unset (we don't know yet).
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        sci->orig_args    contains the original args.
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        sci->args         is the same as sci->orig_args.
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        sci->flags        is zero.
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRINT("SYSCALL[%d,%d](%s) ",
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(getpid)(), tid, VG_SYSNUM_STRING(sysno));
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do any pre-syscall actions */
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(needs).syscall_wrapper) {
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UWord tmpv[8];
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[0] = sci->orig_args.arg1;
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[1] = sci->orig_args.arg2;
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[2] = sci->orig_args.arg3;
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[3] = sci->orig_args.arg4;
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[4] = sci->orig_args.arg5;
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[5] = sci->orig_args.arg6;
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[6] = sci->orig_args.arg7;
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[7] = sci->orig_args.arg8;
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TDICT_CALL(tool_pre_syscall, tid, sysno,
1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &tmpv[0], sizeof(tmpv)/sizeof(tmpv[0]));
1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ent);
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(ent->before);
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (ent->before)( tid,
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  &layout,
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  &sci->args, &sci->status, &sci->flags );
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The pre-handler may have modified:
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sci->args
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sci->status
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sci->flags
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      All else remains unchanged.
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Although the args may be modified, pre handlers are not allowed
1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to change the syscall number.
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now we proceed according to what the pre-handler decided. */
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what == SsHandToKernel
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             || sci->status.what == SsComplete);
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->args.sysno == sci->orig_args.sysno);
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->status.what == SsComplete && !sr_isError(sci->status.sres)) {
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The pre-handler completed the syscall itself, declaring
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         success. */
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sci->flags & SfNoWriteResult) {
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         PRINT(" --> [pre-success] NoWriteResult");
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         PRINT(" --> [pre-success] Success(0x%llx:0x%llx)",
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (ULong)sr_ResHI(sci->status.sres),
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (ULong)sr_Res(sci->status.sres));
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* In this case the allowable flags are to ask for a signal-poll
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and/or a yield after the call.  Changing the args isn't
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         allowed. */
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0 == (sci->flags
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      & ~(SfPollAfter | SfYieldAfter | SfNoWriteResult)));
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(eq_SyscallArgs(&sci->args, &sci->orig_args));
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->status.what == SsComplete && sr_isError(sci->status.sres)) {
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The pre-handler decided to fail syscall itself. */
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      PRINT(" --> [pre-fail] Failure(0x%llx)", (ULong)sr_Err(sci->status.sres));
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* In this case, the pre-handler is also allowed to ask for the
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         post-handler to be run anyway.  Changing the args is not
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         allowed. */
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0 == (sci->flags & ~(SfMayBlock | SfPostOnFail | SfPollAfter)));
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(eq_SyscallArgs(&sci->args, &sci->orig_args));
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->status.what != SsHandToKernel) {
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* huh?! */
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0);
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else /* (sci->status.what == HandToKernel) */ {
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Ok, this is the usual case -- and the complicated one.  There
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         are two subcases: sync and async.  async is the general case
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and is to be used when there is any possibility that the
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         syscall might block [a fact that the pre-handler must tell us
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         via the sci->flags field.]  Because the tidying-away /
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         context-switch overhead of the async case could be large, if
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we are sure that the syscall will not block, we fast-track it
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         by doing it directly in this thread, which is a lot
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         simpler. */
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Check that the given flags are allowable: MayBlock, PollAfter
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and PostOnFail are ok. */
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(0 == (sci->flags & ~(SfMayBlock | SfPostOnFail | SfPollAfter)));
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sci->flags & SfMayBlock) {
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Syscall may block, so run it asynchronously */
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vki_sigset_t mask;
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         PRINT(" --> [async] ... \n");
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask = tst->sig_mask;
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sanitize_client_sigmask(&mask);
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Gack.  More impedance matching.  Copy the possibly
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            modified syscall args back into the guest state. */
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* JRS 2009-Mar-16: if the syscall args are possibly modified,
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            then this assertion is senseless:
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              vg_assert(eq_SyscallArgs(&sci->args, &sci->orig_args));
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            The case that exposed it was sys_posix_spawn on Darwin,
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            which heavily modifies its arguments but then lets the call
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            go through anyway, with SfToBlock set, hence we end up here. */
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putSyscallArgsIntoGuestState( &sci->args, &tst->arch.vex );
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Drop the bigLock */
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(release_BigLock)(tid, VgTs_WaitSys, "VG_(client_syscall)[async]");
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Urr.  We're now in a race against other threads trying to
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            acquire the bigLock.  I guess that doesn't matter provided
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            that do_syscall_for_client only touches thread-local
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            state. */
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Do the call, which operates directly on the guest state,
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            not on our abstracted copies of the args/result. */
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_syscall_for_client(sysno, tst, &mask);
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* do_syscall_for_client may not return if the syscall was
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            interrupted by a signal.  In that case, flow of control is
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            first to m_signals.async_sighandler, which calls
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(fixup_guest_state_after_syscall_interrupted), which
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fixes up the guest state, and possibly calls
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(post_syscall).  Once that's done, control drops back
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            to the scheduler.  */
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Darwin: do_syscall_for_client may not return if the
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            syscall was workq_ops(WQOPS_THREAD_RETURN) and the kernel
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            responded by starting the thread at wqthread_hijack(reuse=1)
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (to run another workqueue item). In that case, wqthread_hijack
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            calls ML_(wqthread_continue), which is similar to
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(fixup_guest_state_after_syscall_interrupted). */
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Reacquire the lock */
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(acquire_BigLock)(tid, "VG_(client_syscall)[async]");
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Even more impedance matching.  Extract the syscall status
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            from the guest state. */
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         getSyscallStatusFromGuestState( &sci->status, &tst->arch.vex );
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vg_assert(sci->status.what == SsComplete);
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Be decorative, if required. */
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(clo_trace_syscalls)) {
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool failed = sr_isError(sci->status.sres);
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (failed) {
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               PRINT("SYSCALL[%d,%d](%s) ... [async] --> Failure(0x%llx)",
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     VG_(getpid)(), tid, VG_SYSNUM_STRING(sysno),
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_Err(sci->status.sres));
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               PRINT("SYSCALL[%d,%d](%s) ... [async] --> "
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     "Success(0x%llx:0x%llx)",
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     VG_(getpid)(), tid, VG_SYSNUM_STRING(sysno),
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_ResHI(sci->status.sres),
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_Res(sci->status.sres) );
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* run the syscall directly */
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* The pre-handler may have modified the syscall args, but
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            since we're passing values in ->args directly to the
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            kernel, there's no point in flushing them back to the
1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            guest state.  Indeed doing so could be construed as
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            incorrect. */
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         SysRes sres
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = VG_(do_syscall)(sysno, sci->args.arg1, sci->args.arg2,
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     sci->args.arg3, sci->args.arg4,
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     sci->args.arg5, sci->args.arg6,
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     sci->args.arg7, sci->args.arg8 );
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sci->status = convert_SysRes_to_SyscallStatus(sres);
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Be decorative, if required. */
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(clo_trace_syscalls)) {
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool failed = sr_isError(sci->status.sres);
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (failed) {
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               PRINT("[sync] --> Failure(0x%llx)",
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_Err(sci->status.sres) );
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               PRINT("[sync] --> Success(0x%llx:0x%llx)",
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_ResHI(sci->status.sres),
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (ULong)sr_Res(sci->status.sres) );
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what == SsComplete);
1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Dump the syscall result back in the guest state.  This is
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a platform-specific action. */
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!(sci->flags & SfNoWriteResult))
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putSyscallStatusIntoGuestState( tid, &sci->status, &tst->arch.vex );
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Situation now:
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - the guest state is now correctly modified following the syscall
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - modified args, original args and syscall status are still
1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        available in the syscallInfo[] entry for this syscall.
1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Now go on to do the post-syscall actions (read on down ..)
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRINT(" ");
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(post_syscall)(tid);
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRINT("\n");
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Perform post syscall actions.  The expected state on entry is
1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   precisely as at the end of VG_(client_syscall), that is:
1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - guest state up to date following the syscall
1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - modified args, original args and syscall status are still
1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     available in the syscallInfo[] entry for this syscall.
1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   - syscall status matches what's in the guest state.
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   There are two ways to get here: the normal way -- being called by
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(client_syscall), and the unusual way, from
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(fixup_guest_state_after_syscall_interrupted).
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Darwin: there's a third way, ML_(wqthread_continue).
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid VG_(post_syscall) (ThreadId tid)
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallInfo*             sci;
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const SyscallTableEntry* ent;
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallStatus            test_status;
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState*             tst;
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Word sysno;
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Preliminaries */
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 1 && tid < VG_N_THREADS);
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst = VG_(get_ThreadState)(tid);
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci = & syscallInfo[tid];
1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* m_signals.sigvgkill_handler might call here even when not in
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a syscall. */
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->status.what == SsIdle || sci->status.what == SsHandToKernel) {
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sci->status.what = SsIdle;
1604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Validate current syscallInfo entry.  In particular we require
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that the current .status matches what's actually in the guest
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      state.  At least in the normal case where we have actually
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      previously written the result into the guest state. */
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what == SsComplete);
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   getSyscallStatusFromGuestState( &test_status, &tst->arch.vex );
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!(sci->flags & SfNoWriteResult))
1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(eq_SyscallStatus( &sci->status, &test_status ));
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Failure of the above assertion on Darwin can indicate a problem
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      in the syscall wrappers that pre-fail or pre-succeed the
1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      syscall, by calling SET_STATUS_Success or SET_STATUS_Failure,
1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when they really should call SET_STATUS_from_SysRes.  The former
1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      create a UNIX-class syscall result on Darwin, which may not be
1621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      correct for the syscall; if that's the case then this assertion
1622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fires.  See PRE(thread_fast_set_cthread_self) for an example.  On
1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      non-Darwin platforms this assertion is should never fail, and this
1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      comment is completely irrelevant. */
1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Ok, looks sane */
1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Get the system call number.  Because the pre-handler isn't
1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allowed to mess with it, it should be the same for both the
1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      original and potentially-modified args. */
1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->args.sysno == sci->orig_args.sysno);
1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sysno = sci->args.sysno;
1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ent = get_syscall_entry(sysno);
1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* pre: status == Complete (asserted above) */
1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Consider either success or failure.  Now run the post handler if:
1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - it exists, and
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      - Success or (Failure and PostOnFail is set)
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ent->after
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && ((!sr_isError(sci->status.sres))
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || (sr_isError(sci->status.sres)
1642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               && (sci->flags & SfPostOnFail) ))) {
1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (ent->after)( tid, &sci->args, &sci->status );
1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Because the post handler might have changed the status (eg, the
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      post-handler for sys_open can change the result from success to
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      failure if the kernel supplied a fd that it doesn't like), once
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      again dump the syscall result back in the guest state.*/
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!(sci->flags & SfNoWriteResult))
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putSyscallStatusIntoGuestState( tid, &sci->status, &tst->arch.vex );
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do any post-syscall actions required by the tool. */
1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(needs).syscall_wrapper) {
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UWord tmpv[8];
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[0] = sci->orig_args.arg1;
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[1] = sci->orig_args.arg2;
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[2] = sci->orig_args.arg3;
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[3] = sci->orig_args.arg4;
1661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[4] = sci->orig_args.arg5;
1662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[5] = sci->orig_args.arg6;
1663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[6] = sci->orig_args.arg7;
1664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tmpv[7] = sci->orig_args.arg8;
1665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_TDICT_CALL(tool_post_syscall, tid,
1666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sysno,
1667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    &tmpv[0], sizeof(tmpv)/sizeof(tmpv[0]),
1668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sci->status.sres);
1669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The syscall is done. */
1672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what == SsComplete);
1673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status.what = SsIdle;
1674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The pre/post wrappers may have concluded that pending signals
1676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      might have been created, and will have set SfPollAfter to
1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      request a poll for them once the syscall is done. */
1678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->flags & SfPollAfter)
1679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(poll_signals)(tid);
1680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Similarly, the wrappers might have asked for a yield
1682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      afterwards. */
1683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sci->flags & SfYieldAfter)
1684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(vg_yield)();
1685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
1689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Dealing with syscalls which get interrupted by a signal:
1690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(fixup_guest_state_after_syscall_interrupted)
1691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
1692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Syscalls done on behalf of the client are finally handed off to the
1694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   kernel in VG_(client_syscall) above, either by calling
1695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_syscall_for_client (the async case), or by calling
1696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(do_syscall6) (the sync case).
1697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If the syscall is not interrupted by a signal (it may block and
1699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   later unblock, but that's irrelevant here) then those functions
1700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   eventually return and so control is passed to VG_(post_syscall).
1701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NB: not sure if the sync case can actually get interrupted, as it
1702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   operates with all signals masked.
1703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   However, the syscall may get interrupted by an async-signal.  In
1705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that case do_syscall_for_client/VG_(do_syscall6) do not
1706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return.  Instead we wind up in m_signals.async_sighandler.  We need
1707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to fix up the guest state to make it look like the syscall was
1708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   interrupted for guest.  So async_sighandler calls here, and this
1709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   does the fixup.  Note that from here we wind up calling
1710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(post_syscall) too.
1711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* These are addresses within ML_(do_syscall_for_client_WRK).  See
1715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscall-$PLAT.S for details.
1716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1717b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#if defined(VGO_linux)
1718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_setup);
1719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_restart);
1720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_complete);
1721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_committed);
1722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_finished);
1723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGO_darwin)
1724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* Darwin requires extra uglyness */
1725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_setup_MACH);
1726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_restart_MACH);
1727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_complete_MACH);
1728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_committed_MACH);
1729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_finished_MACH);
1730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_setup_MDEP);
1731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_restart_MDEP);
1732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_complete_MDEP);
1733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_committed_MDEP);
1734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_finished_MDEP);
1735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_setup_UNIX);
1736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_restart_UNIX);
1737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_complete_UNIX);
1738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_committed_UNIX);
1739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  extern const Addr ML_(blksys_finished_UNIX);
1740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
1741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# error "Unknown OS"
1742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
1743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Back up guest state to restart a system call. */
1746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ML_(fixup_guest_state_to_restart_syscall) ( ThreadArchState* arch )
1748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGP_x86_linux)
1750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_EIP -= 2;             // sizeof(int $0x80)
1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure our caller is actually sane, and we're really backing
1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      back over a syscall.
1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      int $0x80 == CD 80
1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar *p = (UChar *)arch->vex.guest_EIP;
1759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (p[0] != 0xcd || p[1] != 0x80)
1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "?! restarting over syscall at %#x %02x %02x\n",
1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      arch->vex.guest_EIP, p[0], p[1]);
1764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(p[0] == 0xcd && p[1] == 0x80);
1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_linux)
1769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_RIP -= 2;             // sizeof(syscall)
1770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure our caller is actually sane, and we're really backing
1772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      back over a syscall.
1773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      syscall == 0F 05
1775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar *p = (UChar *)arch->vex.guest_RIP;
1778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (p[0] != 0x0F || p[1] != 0x05)
1780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
1781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "?! restarting over syscall at %#llx %02x %02x\n",
1782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      arch->vex.guest_RIP, p[0], p[1]);
1783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(p[0] == 0x0F && p[1] == 0x05);
1785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_CIA -= 4;             // sizeof(ppc32 instr)
1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure our caller is actually sane, and we're really backing
1791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      back over a syscall.
1792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sc == 44 00 00 02
1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar *p = (UChar *)arch->vex.guest_CIA;
1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (p[0] != 0x44 || p[1] != 0x0 || p[2] != 0x0 || p[3] != 0x02)
1799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
1800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "?! restarting over syscall at %#llx %02x %02x %02x %02x\n",
1801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      arch->vex.guest_CIA + 0ULL, p[0], p[1], p[2], p[3]);
1802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(p[0] == 0x44 && p[1] == 0x0 && p[2] == 0x0 && p[3] == 0x2);
1804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_arm_linux)
1807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (arch->vex.guest_R15T & 1) {
1808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Thumb mode.  SVC is a encoded as
1809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   1101 1111 imm8
1810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // where imm8 is the SVC number, and we only accept 0.
1811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arch->vex.guest_R15T -= 2;   // sizeof(thumb 16 bit insn)
1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* p     = (UChar*)(arch->vex.guest_R15T - 1);
1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   valid = p[0] == 0 && p[1] == 0xDF;
1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!valid) {
1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "?! restarting over (Thumb) syscall that is not syscall "
1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "at %#llx %02x %02x\n",
1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      arch->vex.guest_R15T - 1ULL, p[0], p[1]);
1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(valid);
1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // FIXME: NOTE, this really isn't right.  We need to back up
1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // ITSTATE to what it was before the SVC instruction, but we
1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // don't know what it was.  At least assert that it is now
1824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // zero, because if it is nonzero then it must also have
1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // been nonzero for the SVC itself, which means it was
1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // conditional.  Urk.
1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(arch->vex.guest_ITSTATE == 0);
1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // ARM mode.  SVC is encoded as
1830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      //   cond 1111 imm24
1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // where imm24 is the SVC number, and we only accept 0.
1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      arch->vex.guest_R15T -= 4;   // sizeof(arm instr)
1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* p     = (UChar*)arch->vex.guest_R15T;
1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   valid = p[0] == 0 && p[1] == 0 && p[2] == 0
1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     && (p[3] & 0xF) == 0xF;
1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!valid) {
1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_DebugMsg,
1838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "?! restarting over (ARM) syscall that is not syscall "
1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "at %#llx %02x %02x %02x %02x\n",
1840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      arch->vex.guest_R15T + 0ULL, p[0], p[1], p[2], p[3]);
1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(valid);
1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_x86_darwin)
1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   arch->vex.guest_EIP = arch->vex.guest_IP_AT_SYSCALL;
1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Make sure our caller is actually sane, and we're really backing
1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      back over a syscall.
1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      int $0x80 == CD 80
1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      int $0x81 == CD 81
1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      int $0x82 == CD 82
1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sysenter  == 0F 34
1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       UChar *p = (UChar *)arch->vex.guest_EIP;
1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       Bool  ok = (p[0] == 0xCD && p[1] == 0x80)
1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  || (p[0] == 0xCD && p[1] == 0x81)
1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  || (p[0] == 0xCD && p[1] == 0x82)
1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  || (p[0] == 0x0F && p[1] == 0x34);
1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       if (!ok)
1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           VG_(message)(Vg_DebugMsg,
1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        "?! restarting over syscall at %#x %02x %02x\n",
1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        arch->vex.guest_EIP, p[0], p[1]);
1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       vg_assert(ok);
1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#elif defined(VGP_amd64_darwin)
1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // DDD: #warning GrP fixme amd64 restart unimplemented
1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1873b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#elif defined(VGP_s390x_linux)
1874b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   arch->vex.guest_IA -= 2;             // sizeof(syscall)
1875b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1876b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Make sure our caller is actually sane, and we're really backing
1877b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      back over a syscall.
1878b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1879b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      syscall == 0A <num>
1880b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   */
1881b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   {
1882b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      UChar *p = (UChar *)arch->vex.guest_IA;
1883b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (p[0] != 0x0A)
1884b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(message)(Vg_DebugMsg,
1885b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      "?! restarting over syscall at %#llx %02x %02x\n",
1886b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                      arch->vex.guest_IA, p[0], p[1]);
1887b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1888b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vg_assert(p[0] == 0x0A);
1889b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
1890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#else
1891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  error "ML_(fixup_guest_state_to_restart_syscall): unknown plat"
1892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
1893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
1896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Fix up the guest state when a syscall is interrupted by a signal
1897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and so has been forced to return 'sysret'.
1898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   To do this, we determine the precise state of the syscall by
1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   looking at the (real) IP at the time the signal happened.  The
1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscall sequence looks like:
1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     1. unblock signals
1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     2. perform syscall
1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     3. save result to guest state (EAX, RAX, R3+CR0.SO)
1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     4. re-block signals
1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If a signal
1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   happens at      Then     Why?
1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [1-2)           restart  nothing has happened (restart syscall)
1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [2]             restart  syscall hasn't started, or kernel wants to restart
1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [2-3)           save     syscall complete, but results not saved
1913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   [3-4)           syscall complete, results saved
1914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Sometimes we never want to restart an interrupted syscall (because
1916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sigaction says not to), so we only restart if "restart" is True.
1917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This will also call VG_(post_syscall) if the syscall has actually
1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   completed (either because it was interrupted, or because it
1920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   actually finished).  It will not call VG_(post_syscall) if the
1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   syscall is set up for restart, which means that the pre-wrapper may
1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   get called multiple times.
1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid
1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownVG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid,
1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  Addr     ip,
1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  SysRes   sres,
1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                  Bool     restart)
1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Note that we don't know the syscall number here, since (1) in
1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      general there's no reliable way to get hold of it short of
1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stashing it in the guest state before the syscall, and (2) in
1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      any case we don't need to know it for the actions done by this
1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      routine.
1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Furthermore, 'sres' is only used in the case where the syscall
1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is complete, but the result has not been committed to the guest
1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      state yet.  In any other situation it will be meaningless and
1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      therefore ignored. */
1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState*     tst;
1943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallStatus    canonical;
1944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadArchState* th_regs;
1945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallInfo*     sci;
1946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Compute some Booleans indicating which range we're in. */
1948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool outside_range,
1949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        in_setup_to_restart,      // [1,2) in the .S files
1950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        at_restart,               // [2]   in the .S files
1951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        in_complete_to_committed, // [3,4) in the .S files
1952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        in_committed_to_finished; // [4,5) in the .S files
1953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1954b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov#  if defined(VGO_linux)
1955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   outside_range
1956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ip < ML_(blksys_setup) || ip >= ML_(blksys_finished);
1957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_setup_to_restart
1958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ip >= ML_(blksys_setup) && ip < ML_(blksys_restart);
1959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   at_restart
1960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ip == ML_(blksys_restart);
1961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_complete_to_committed
1962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ip >= ML_(blksys_complete) && ip < ML_(blksys_committed);
1963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_committed_to_finished
1964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ip >= ML_(blksys_committed) && ip < ML_(blksys_finished);
1965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  elif defined(VGO_darwin)
1966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   outside_range
1967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      =  (ip < ML_(blksys_setup_MACH) || ip >= ML_(blksys_finished_MACH))
1968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      && (ip < ML_(blksys_setup_MDEP) || ip >= ML_(blksys_finished_MDEP))
1969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      && (ip < ML_(blksys_setup_UNIX) || ip >= ML_(blksys_finished_UNIX));
1970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_setup_to_restart
1971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      =  (ip >= ML_(blksys_setup_MACH) && ip < ML_(blksys_restart_MACH))
1972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_setup_MDEP) && ip < ML_(blksys_restart_MDEP))
1973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_setup_UNIX) && ip < ML_(blksys_restart_UNIX));
1974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   at_restart
1975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      =  (ip == ML_(blksys_restart_MACH))
1976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip == ML_(blksys_restart_MDEP))
1977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip == ML_(blksys_restart_UNIX));
1978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_complete_to_committed
1979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      =  (ip >= ML_(blksys_complete_MACH) && ip < ML_(blksys_committed_MACH))
1980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_complete_MDEP) && ip < ML_(blksys_committed_MDEP))
1981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_complete_UNIX) && ip < ML_(blksys_committed_UNIX));
1982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in_committed_to_finished
1983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      =  (ip >= ML_(blksys_committed_MACH) && ip < ML_(blksys_finished_MACH))
1984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_committed_MDEP) && ip < ML_(blksys_finished_MDEP))
1985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      || (ip >= ML_(blksys_committed_UNIX) && ip < ML_(blksys_finished_UNIX));
1986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Wasn't that just So Much Fun?  Does your head hurt yet?  Mine does. */
1987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  else
1988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    error "Unknown OS"
1989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
1990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_trace_signals))
1992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)( Vg_DebugMsg,
1993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "interrupted_syscall: tid=%d, ip=0x%llx, "
1994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "restart=%s, sres.isErr=%s, sres.val=%lld\n",
1995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    (Int)tid,
1996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    (ULong)ip,
1997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    restart ? "True" : "False",
1998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    sr_isError(sres) ? "True" : "False",
1999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    (Long)(sr_isError(sres) ? sr_Err(sres) : sr_Res(sres)) );
2000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
2002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 1 && tid < VG_N_THREADS);
2003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
2004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst     = VG_(get_ThreadState)(tid);
2006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   th_regs = &tst->arch;
2007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci     = & syscallInfo[tid];
2008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Figure out what the state of the syscall was by examining the
2010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (real) IP at the time of the signal, and act accordingly. */
2011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (outside_range) {
2012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals))
2013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)( Vg_DebugMsg,
2014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "  not in syscall at all: hmm, very suspicious\n" );
2015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Looks like we weren't in a syscall at all.  Hmm. */
2016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(sci->status.what != SsIdle);
2017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return;
2018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We should not be here unless this thread had first started up
2021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the machinery for a syscall by calling VG_(client_syscall).
2022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Hence: */
2023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what != SsIdle);
2024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* now, do one of four fixup actions, depending on where the IP has
2026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      got to. */
2027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (in_setup_to_restart) {
2029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* syscall hasn't even started; go around again */
2030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals))
2031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)( Vg_DebugMsg, "  not started: restarting\n");
2032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(sci->status.what == SsHandToKernel);
2033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(fixup_guest_state_to_restart_syscall)(th_regs);
2034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (at_restart) {
2038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We're either about to run the syscall, or it was interrupted
2039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and the kernel restarted it.  Restart if asked, otherwise
2040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         EINTR it. */
2041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (restart) {
2042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(clo_trace_signals))
2043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(message)( Vg_DebugMsg, "  at syscall instr: restarting\n");
2044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ML_(fixup_guest_state_to_restart_syscall)(th_regs);
2045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (VG_(clo_trace_signals))
2047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(message)( Vg_DebugMsg, "  at syscall instr: returning EINTR\n");
2048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         canonical = convert_SysRes_to_SyscallStatus(
2049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        VG_(mk_SysRes_Error)( VKI_EINTR )
2050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
2051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!(sci->flags & SfNoWriteResult))
2052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putSyscallStatusIntoGuestState( tid, &canonical, &th_regs->vex );
2053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sci->status = canonical;
2054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(post_syscall)(tid);
2055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (in_complete_to_committed) {
2060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Syscall complete, but result hasn't been written back yet.
2061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Write the SysRes we were supplied with back to the guest
2062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         state. */
2063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals))
2064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)( Vg_DebugMsg,
2065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "  completed, but uncommitted: committing\n");
2066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      canonical = convert_SysRes_to_SyscallStatus( sres );
2067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(sci->flags & SfNoWriteResult))
2068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putSyscallStatusIntoGuestState( tid, &canonical, &th_regs->vex );
2069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sci->status = canonical;
2070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(post_syscall)(tid);
2071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (in_committed_to_finished) {
2075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Result committed, but the signal mask has not been restored;
2076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we expect our caller (the signal handler) will have fixed
2077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this up. */
2078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (VG_(clo_trace_signals))
2079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)( Vg_DebugMsg,
2080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "  completed and committed: nothing to do\n");
2081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      getSyscallStatusFromGuestState( &sci->status, &th_regs->vex );
2082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vg_assert(sci->status.what == SsComplete);
2083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(post_syscall)(tid);
2084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
2087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(core_panic)("?? strange syscall interrupt state?");
2088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* In all cases, the syscall is now finished (even if we called
2090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ML_(fixup_guest_state_to_restart_syscall), since that just
2091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      re-positions the guest's IP for another go at it).  So we need
2092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to record that fact. */
2093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status.what = SsIdle;
2094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#if defined(VGO_darwin)
2098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Clean up after workq_ops(WQOPS_THREAD_RETURN) jumped to wqthread_hijack.
2099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This is similar to VG_(fixup_guest_state_after_syscall_interrupted).
2100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This longjmps back to the scheduler.
2101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid ML_(wqthread_continue_NORETURN)(ThreadId tid)
2102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ThreadState*     tst;
2104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SyscallInfo*     sci;
2105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(acquire_BigLock)(tid, "wqthread_continue_NORETURN");
2107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   PRINT("SYSCALL[%d,%d](%s) workq_ops() starting new workqueue item\n",
2109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(getpid)(), tid, VG_SYSNUM_STRING(__NR_workq_ops));
2110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_valid_tid)(tid));
2112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tid >= 1 && tid < VG_N_THREADS);
2113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(VG_(is_running_thread)(tid));
2114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tst     = VG_(get_ThreadState)(tid);
2116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci     = & syscallInfo[tid];
2117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(sci->status.what != SsIdle);
2118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tst->os_state.wq_jmpbuf_valid);  // check this BEFORE post_syscall
2119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Pretend the syscall completed normally, but don't touch the thread state.
2121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status = convert_SysRes_to_SyscallStatus( VG_(mk_SysRes_Success)(0) );
2122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->flags |= SfNoWriteResult;
2123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(post_syscall)(tid);
2124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sci->status.what = SsIdle;
2126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(tst->sched_jmpbuf_valid);
2128b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_MINIMAL_LONGJMP(tst->sched_jmpbuf);
2129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* NOTREACHED */
2131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vg_assert(0);
2132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
2134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ---------------------------------------------------------------------
2137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   A place to store the where-to-call-when-really-done pointer
2138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------------------------------------------ */
2139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// When the final thread is done, where shall I call to shutdown the
2141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// system cleanly?  Is set once at startup (in m_main) and never
2142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// changes after that.  Is basically a pointer to the exit
2143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// continuation.  This is all just a nasty hack to avoid calling
2144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// directly from m_syswrap to m_main at exit, since that would cause
2145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// m_main to become part of a module cycle, which is silly.
2146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid (* VG_(address_of_m_main_shutdown_actions_NORETURN) )
2147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       (ThreadId,VgSchedReturnCode)
2148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   = NULL;
2149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
2151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                                          ---*/
2152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
2153