/*--------------------------------------------------------------------*/ /*--- 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 ---*/ /*--------------------------------------------------------------------*/