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