blob: 26a82f7abd2f8a329c7e0779f0b344ba87cbb2a3 [file] [log] [blame]
/*--------------------------------------------------------------------*/
/*--- Types and macros for writing syscall wrappers. ---*/
/*--- priv_types_n_macros.h ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2013 Julian Seward
jseward@acm.org
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
#ifndef __PRIV_TYPES_N_MACROS_H
#define __PRIV_TYPES_N_MACROS_H
#include "pub_core_basics.h" // Addr
/* requires #include "pub_core_options.h" */
/* requires #include "pub_core_signals.h" */
/* This header defines types and macros which are useful for writing
syscall wrappers. It does not give prototypes for any such
headers, though: that is the job of the priv_syswrap-*.h headers.
This header gets included in any file which defines or declares
wrappers, and as such should only contain stuff which is relevant
to all such files.
*/
/* ---------------------------------------------------------------------
Types that are used in syscall wrappers.
------------------------------------------------------------------ */
/* Arguments for a syscall. */
typedef
struct SyscallArgs {
Word sysno;
UWord arg1;
UWord arg2;
UWord arg3;
UWord arg4;
UWord arg5;
UWord arg6;
UWord arg7;
UWord arg8;
}
SyscallArgs;
/* Current status of a syscall being done on behalf of the client. */
typedef
struct SyscallStatus {
enum {
/* call is complete, result is in 'res' */
SsComplete=1,
/* syscall not yet completed; must be handed to the kernel */
SsHandToKernel,
/* not currently handling a syscall for this thread */
SsIdle
} what;
SysRes sres; /* only meaningful for .what == SsComplete */
}
SyscallStatus;
/* Guest state layout info for syscall args. */
typedef
struct {
// Note that, depending on the platform, arguments may be found in
// registers or on the stack. (See the comment at the top of
// syswrap-main.c for per-platform details.) For register arguments
// (which have o_arg field names) the o_arg value is the offset into
// the vex register state. For stack arguments (which have s_arg
// field names), the s_arg value is the offset from the stack pointer.
Int o_sysno;
# if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
|| defined(VGP_ppc32_linux) \
|| defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \
|| defined(VGP_arm_linux) || defined(VGP_s390x_linux) \
|| defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \
|| defined(VGP_tilegx_linux)
Int o_arg1;
Int o_arg2;
Int o_arg3;
Int o_arg4;
Int o_arg5;
Int o_arg6;
Int uu_arg7;
Int uu_arg8;
# elif defined(VGP_mips32_linux)
Int o_arg1;
Int o_arg2;
Int o_arg3;
Int o_arg4;
Int s_arg5;
Int s_arg6;
Int uu_arg7;
Int uu_arg8;
# elif defined(VGP_x86_darwin)
Int s_arg1;
Int s_arg2;
Int s_arg3;
Int s_arg4;
Int s_arg5;
Int s_arg6;
Int s_arg7;
Int s_arg8;
# elif defined(VGP_amd64_darwin)
Int o_arg1;
Int o_arg2;
Int o_arg3;
Int o_arg4;
Int o_arg5;
Int o_arg6;
Int s_arg7;
Int s_arg8;
# else
# error "Unknown platform"
# endif
}
SyscallArgLayout;
/* Flags describing syscall wrappers */
#define SfMayBlock (1 << 1) /* may block */
#define SfPostOnFail (1 << 2) /* call POST() function on failure */
#define SfPollAfter (1 << 3) /* poll for signals on completion */
#define SfYieldAfter (1 << 4) /* yield on completion */
#define SfNoWriteResult (1 << 5) /* don't write result to guest state */
/* ---------------------------------------------------------------------
The syscall table.
------------------------------------------------------------------ */
typedef
struct {
void (*before) ( ThreadId,
SyscallArgLayout*,
/*MOD*/SyscallArgs*,
/*OUT*/SyscallStatus*,
/*OUT*/UWord*
);
void (*after) ( ThreadId,
SyscallArgs*,
SyscallStatus*
);
}
SyscallTableEntry;
/* Syscall table entries bind __NR_xxx syscall numbers to the PRE/POST
wrappers for the relevant syscall used in the OS kernel for that
number. Note that the constant names don't always match the
wrapper names in a straightforward way. For example, on x86/Linux:
__NR_lchown --> sys_lchown16()
__NR_lchown32 --> sys_lchown()
__NR_select --> old_select()
__NR__newselect --> sys_select()
*/
/* A function to find the syscall table entry for a given sysno. If
none is found, return NULL. This used to be done with a single
fixed sized table exposed to the caller, but that's too inflexible;
hence now use a function which can do arbitrary messing around to
find the required entry. */
#if defined(VGP_mips32_linux)
/* Up to 6 parameters, 4 in registers 2 on stack. */
# define PRA1(s,t,a) PRRAn(1,s,t,a)
# define PRA2(s,t,a) PRRAn(2,s,t,a)
# define PRA3(s,t,a) PRRAn(3,s,t,a)
# define PRA4(s,t,a) PRRAn(4,s,t,a)
# define PRA5(s,t,a) PSRAn(5,s,t,a)
# define PRA6(s,t,a) PSRAn(6,s,t,a)
#endif
#if defined(VGO_linux)
extern
SyscallTableEntry* ML_(get_linux_syscall_entry)( UInt sysno );
#elif defined(VGO_darwin)
/* XXX: Darwin still uses the old scheme of exposing the table
array(s) and size(s) directly to syswrap-main.c. This should be
fixed. */
extern const SyscallTableEntry ML_(syscall_table)[];
extern const UInt ML_(syscall_table_size);
#else
# error Unknown OS
#endif
/* ---------------------------------------------------------------------
Declaring and defining wrappers.
------------------------------------------------------------------ */
/* Templates for generating the PRE and POST macros -- that is, the
formal parameter lists for the definitions of wrapper functions.
Since these names exist in the global namespace, 'auxstr' should
give an auxiliary string, eg, "generic", "x86_linux", "linux", etc,
that ensures the names won't clash with other wrappers.
You should create corresponding global declarations using
DECL_TEMPLATE (indirectly) below.
Note. The silly name "arrghs" is used rather than just "args"
because a few wrappers declare the name "args" themselves, and
renaming those decls can change the name that comes out in error
messages (on scalar arg checks). Hence rename this instead.
*/
#define DEFN_PRE_TEMPLATE(auxstr, name) \
void vgSysWrap_##auxstr##_##name##_before \
( ThreadId tid, \
SyscallArgLayout* layout, \
/*MOD*/SyscallArgs* arrghs, \
/*OUT*/SyscallStatus* status, \
/*OUT*/UWord* flags \
)
#define DEFN_POST_TEMPLATE(auxstr, name) \
void vgSysWrap_##auxstr##_##name##_after \
( ThreadId tid, \
SyscallArgs* arrghs, \
SyscallStatus* status \
)
/* This macro generates declarations (prototypes) for wrappers. It
declares both the pre-wrapper and the post-wrapper, even though the
post-wrapper may not actually exist.
*/
#define DECL_TEMPLATE(auxstr, name) \
extern \
void vgSysWrap_##auxstr##_##name##_before \
( ThreadId tid, \
SyscallArgLayout* layout, \
/*MOD*/SyscallArgs* arrghs, \
/*OUT*/SyscallStatus* status, \
/*OUT*/UWord* flags \
); \
extern \
void vgSysWrap_##auxstr##_##name##_after \
( ThreadId tid, \
SyscallArgs* arrghs, \
SyscallStatus* status \
);
/* Macros for conveniently generating entries in the syscall
tables. This first pair are not used directly. */
#define WRAPPER_ENTRY_X_(auxstr, sysno, name) \
[sysno] = { vgSysWrap_##auxstr##_##name##_before, NULL }
#define WRAPPER_ENTRY_XY(auxstr, sysno, name) \
[sysno] = { vgSysWrap_##auxstr##_##name##_before, \
vgSysWrap_##auxstr##_##name##_after }
#define WRAPPER_PRE_NAME(auxstr, name) \
vgSysWrap_##auxstr##_##name##_before
#define WRAPPER_POST_NAME(auxstr, name) \
vgSysWrap_##auxstr##_##name##_after
/* Add a generic wrapper to a syscall table. */
#if defined(VGO_linux)
# define GENX_(sysno, name) WRAPPER_ENTRY_X_(generic, sysno, name)
# define GENXY(sysno, name) WRAPPER_ENTRY_XY(generic, sysno, name)
#elif defined(VGO_darwin)
# define GENX_(sysno, name) WRAPPER_ENTRY_X_(generic, VG_DARWIN_SYSNO_INDEX(sysno), name)
# define GENXY(sysno, name) WRAPPER_ENTRY_XY(generic, VG_DARWIN_SYSNO_INDEX(sysno), name)
#else
# error Unknown OS
#endif
/* Add a Linux-specific, arch-independent wrapper to a syscall
table. */
#define LINX_(sysno, name) WRAPPER_ENTRY_X_(linux, sysno, name)
#define LINXY(sysno, name) WRAPPER_ENTRY_XY(linux, sysno, name)
/* ---------------------------------------------------------------------
Macros useful for writing wrappers concisely. These refer to the
parameters declared by DEFN_{PRE,POST}_TEMPLATE and so in a way do
not help clarity of understanding. But they are just too useful to
omit.
------------------------------------------------------------------ */
/* Reference to the syscall's arguments -- the ones which the
pre-wrapper may have modified, not the original copy. */
#define SYSNO (arrghs->sysno)
#define ARG1 (arrghs->arg1)
#define ARG2 (arrghs->arg2)
#define ARG3 (arrghs->arg3)
#define ARG4 (arrghs->arg4)
#define ARG5 (arrghs->arg5)
#define ARG6 (arrghs->arg6)
#define ARG7 (arrghs->arg7)
#define ARG8 (arrghs->arg8)
/* Reference to the syscall's current result status/value. General
paranoia all round. */
#define SUCCESS (status->what == SsComplete && !sr_isError(status->sres))
#define FAILURE (status->what == SsComplete && sr_isError(status->sres))
#define SWHAT (status->what)
#define RES (getRES(status))
#define RESHI (getRESHI(status))
#define ERR (getERR(status))
static inline UWord getRES ( SyscallStatus* st ) {
vg_assert(st->what == SsComplete);
vg_assert(!sr_isError(st->sres));
return sr_Res(st->sres);
}
#if defined(VGO_darwin)
static inline UWord getRESHI ( SyscallStatus* st ) {
vg_assert(st->what == SsComplete);
vg_assert(!sr_isError(st->sres));
return sr_ResHI(st->sres);
}
#endif
static inline UWord getERR ( SyscallStatus* st ) {
vg_assert(st->what == SsComplete);
vg_assert(sr_isError(st->sres));
return sr_Err(st->sres);
}
/* Set the current result status/value in various ways. */
#define SET_STATUS_Success(zzz) \
do { status->what = SsComplete; \
status->sres = VG_(mk_SysRes_Success)(zzz); \
} while (0)
#define SET_STATUS_Failure(zzz) \
do { Word wzz = (Word)(zzz); \
/* Catch out wildly bogus error values. */ \
vg_assert(wzz >= 0 && wzz < 10000); \
status->what = SsComplete; \
status->sres = VG_(mk_SysRes_Error)(wzz); \
} while (0)
#define SET_STATUS_from_SysRes(zzz) \
do { \
status->what = SsComplete; \
status->sres = (zzz); \
} while (0)
#define PRINT(format, args...) \
if (VG_(clo_trace_syscalls)) \
VG_(printf)(format, ## args)
#define FUSE_COMPATIBLE_MAY_BLOCK() \
if (SimHintiS(SimHint_fuse_compatible, VG_(clo_sim_hints))) \
*flags |= SfMayBlock
/* Macros used to tell tools about uses of scalar arguments. Note,
these assume little-endianness. These can only be used in
pre-wrappers, and they refer to the layout parameter passed in. */
/* PRRSN == "pre-register-read-sysno"
PRRAn == "pre-register-read-argument"
PSRAn == "pre-stack-read-argument"
PRAn == "pre-read-argument"
*/
#if defined(VGP_mips32_linux)
/* Up to 6 parameters, 4 in registers 2 on stack. */
# define PRA1(s,t,a) PRRAn(1,s,t,a)
# define PRA2(s,t,a) PRRAn(2,s,t,a)
# define PRA3(s,t,a) PRRAn(3,s,t,a)
# define PRA4(s,t,a) PRRAn(4,s,t,a)
# define PRA5(s,t,a) PSRAn(5,s,t,a)
# define PRA6(s,t,a) PSRAn(6,s,t,a)
#elif defined(VGO_linux) && !defined(VGP_mips32_linux)
/* Up to 6 parameters, all in registers. */
# define PRA1(s,t,a) PRRAn(1,s,t,a)
# define PRA2(s,t,a) PRRAn(2,s,t,a)
# define PRA3(s,t,a) PRRAn(3,s,t,a)
# define PRA4(s,t,a) PRRAn(4,s,t,a)
# define PRA5(s,t,a) PRRAn(5,s,t,a)
# define PRA6(s,t,a) PRRAn(6,s,t,a)
#elif defined(VGP_x86_darwin)
/* Up to 8 parameters, all on the stack. */
# define PRA1(s,t,a) PSRAn(1,s,t,a)
# define PRA2(s,t,a) PSRAn(2,s,t,a)
# define PRA3(s,t,a) PSRAn(3,s,t,a)
# define PRA4(s,t,a) PSRAn(4,s,t,a)
# define PRA5(s,t,a) PSRAn(5,s,t,a)
# define PRA6(s,t,a) PSRAn(6,s,t,a)
# define PRA7(s,t,a) PSRAn(7,s,t,a)
# define PRA8(s,t,a) PSRAn(8,s,t,a)
#elif defined(VGP_amd64_darwin)
/* Up to 8 parameters, 6 in registers, 2 on the stack. */
# define PRA1(s,t,a) PRRAn(1,s,t,a)
# define PRA2(s,t,a) PRRAn(2,s,t,a)
# define PRA3(s,t,a) PRRAn(3,s,t,a)
# define PRA4(s,t,a) PRRAn(4,s,t,a)
# define PRA5(s,t,a) PRRAn(5,s,t,a)
# define PRA6(s,t,a) PRRAn(6,s,t,a)
# define PRA7(s,t,a) PSRAn(7,s,t,a)
# define PRA8(s,t,a) PSRAn(8,s,t,a)
#else
# error Unknown platform
#endif
/* Tell the tool that the syscall number is being read. */
#define PRRSN \
VG_(tdict).track_pre_reg_read(Vg_CoreSysCall, tid, "(syscallno)", \
layout->o_sysno, sizeof(UWord));
/* REGISTER PARAMETERS */
/* PRRAn: Tell the tool that the register holding the n-th syscall
argument is being read, at type 't' which must be at most the size
of a register but can be smaller. In the latter case we need to be
careful about endianness. */
/* little-endian: the part of the guest state being read is
let here = offset_of_reg
in [here .. here + sizeof(t) - 1]
since the least significant parts of the guest register are stored
in memory at the lowest address.
*/
#define PRRAn_LE(n,s,t,a) \
do { \
Int here = layout->o_arg##n; \
vg_assert(sizeof(t) <= sizeof(UWord)); \
vg_assert(here >= 0); \
VG_(tdict).track_pre_reg_read( \
Vg_CoreSysCall, tid, s"("#a")", \
here, sizeof(t) \
); \
} while (0)
/* big-endian: the part of the guest state being read is
let next = offset_of_reg + sizeof(reg)
in [next - sizeof(t) .. next - 1]
since the least significant parts of the guest register are stored
in memory at the highest address.
*/
#define PRRAn_BE(n,s,t,a) \
do { \
Int here = layout->o_arg##n; \
Int next = layout->o_arg##n + sizeof(UWord); \
vg_assert(sizeof(t) <= sizeof(UWord)); \
vg_assert(here >= 0); \
VG_(tdict).track_pre_reg_read( \
Vg_CoreSysCall, tid, s"("#a")", \
next-sizeof(t), sizeof(t) \
); \
} while (0)
#if defined(VG_BIGENDIAN)
# define PRRAn(n,s,t,a) PRRAn_BE(n,s,t,a)
#elif defined(VG_LITTLEENDIAN)
# define PRRAn(n,s,t,a) PRRAn_LE(n,s,t,a)
#else
# error "Unknown endianness"
#endif
/* STACK PARAMETERS */
/* PSRAn: Tell the tool that the memory holding the n-th syscall
argument is being read, at type 't' which must be at most the size
of a register but can be smaller. In the latter case we need to be
careful about endianness. */
/* little-endian: the part of the guest state being read is
let here = offset_of_reg
in [here .. here + sizeof(t) - 1]
since the least significant parts of the guest register are stored
in memory at the lowest address.
*/
#define PSRAn_LE(n,s,t,a) \
do { \
Addr here = layout->s_arg##n + VG_(get_SP)(tid); \
vg_assert(sizeof(t) <= sizeof(UWord)); \
VG_(tdict).track_pre_mem_read( \
Vg_CoreSysCallArgInMem, tid, s"("#a")", \
here, sizeof(t) \
); \
} while (0)
/* big-endian: the part of the guest state being read is
let next = offset_of_reg + sizeof(reg)
in [next - sizeof(t) .. next - 1]
since the least significant parts of the guest register are stored
in memory at the highest address.
*/
#if (defined(VGP_mips32_linux) && defined (_MIPSEB))
#define PSRAn_BE(n,s,t,a) \
do { \
Addr next = layout->s_arg##n + sizeof(UWord) + \
VG_(get_SP)(tid); \
vg_assert(sizeof(t) <= sizeof(UWord)); \
VG_(tdict).track_pre_mem_read( \
Vg_CoreSysCallArgInMem, tid, s"("#a")", \
next-sizeof(t), sizeof(t) \
); \
} while (0)
#else
#define PSRAn_BE(n,s,t,a) \
do { \
Addr next = layout->o_arg##n + sizeof(UWord) + \
VG_(threads)[tid].arch.vex.VG_STACK_PTR; \
vg_assert(sizeof(t) <= sizeof(UWord)); \
VG_(tdict).track_pre_mem_read( \
Vg_CoreSysCallArgInMem, tid, s"("#a")", \
next-sizeof(t), sizeof(t) \
); \
} while (0)
#endif
#if defined(VG_BIGENDIAN)
# define PSRAn(n,s,t,a) PSRAn_BE(n,s,t,a)
#elif defined(VG_LITTLEENDIAN)
# define PSRAn(n,s,t,a) PSRAn_LE(n,s,t,a)
#else
# error "Unknown endianness"
#endif
#define PRE_REG_READ0(tr, s) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
}
#define PRE_REG_READ1(tr, s, t1, a1) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
PRA1(s,t1,a1); \
}
#define PRE_REG_READ2(tr, s, t1, a1, t2, a2) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
PRA1(s,t1,a1); PRA2(s,t2,a2); \
}
#define PRE_REG_READ3(tr, s, t1, a1, t2, a2, t3, a3) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
}
#define PRE_REG_READ4(tr, s, t1, a1, t2, a2, t3, a3, t4, a4) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
PRA4(s,t4,a4); \
}
#define PRE_REG_READ5(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
PRA4(s,t4,a4); PRA5(s,t5,a5); \
}
#define PRE_REG_READ6(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6); \
}
#define PRE_REG_READ7(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6, t7, a7) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6); \
PRA7(s,t7,a7); \
}
#define PRE_REG_READ8(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6, t7, a7, t8, a8) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6); \
PRA7(s,t7,a7); PRA8(s,t8,a8); \
}
#define PRE_MEM_READ(zzname, zzaddr, zzlen) \
VG_TRACK( pre_mem_read, Vg_CoreSysCall, tid, zzname, zzaddr, zzlen)
#define PRE_MEM_RASCIIZ(zzname, zzaddr) \
VG_TRACK( pre_mem_read_asciiz, Vg_CoreSysCall, tid, zzname, zzaddr)
#define PRE_MEM_WRITE(zzname, zzaddr, zzlen) \
VG_TRACK( pre_mem_write, Vg_CoreSysCall, tid, zzname, zzaddr, zzlen)
#define POST_MEM_WRITE(zzaddr, zzlen) \
VG_TRACK( post_mem_write, Vg_CoreSysCall, tid, zzaddr, zzlen)
#define PRE_FIELD_READ(zzname, zzfield) \
PRE_MEM_READ(zzname, (UWord)&zzfield, sizeof(zzfield))
#define PRE_FIELD_WRITE(zzname, zzfield) \
PRE_MEM_WRITE(zzname, (UWord)&zzfield, sizeof(zzfield))
#define POST_FIELD_WRITE(zzfield) \
POST_MEM_WRITE((UWord)&zzfield, sizeof(zzfield))
#endif // __PRIV_TYPES_N_MACROS_H
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/