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 {
- enum { SsSuccess=1, SsFailure, SsHandToKernel, SsIdle } what;
- UWord val; /* only meaningful for .what == Success or Failure */
+ 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;
Int o_arg4;
Int o_arg5;
Int o_arg6;
+ Int o_arg8;
+ Int o_arg7;
Int o_retval;
}
SyscallArgLayout;
*/
-/* These are defined in the relevant platform-specific files --
- syswrap-arch-os.c */
+#if defined(VGO_linux)
+/* On Linux, finding the wrapper is easy: just look up in fixed,
+ platform-specific tables. These are defined in the relevant
+ platform-specific files -- syswrap-arch-os.c */
extern const SyscallTableEntry ML_(syscall_table)[];
extern const UInt ML_(syscall_table_size);
-
+
+#elif defined(VGP_ppc32_aix5)
+/* On AIX5 this is more complex than the simple fixed table lookup on
+ Linux, since the syscalls don't have fixed numbers. So it's
+ simplest to use a function, which does all the required messing
+ around. */
+extern
+SyscallTableEntry* ML_(get_ppc32_aix5_syscall_entry) ( UInt sysno );
+
+#elif defined(VGP_ppc64_aix5)
+extern
+SyscallTableEntry* ML_(get_ppc64_aix5_syscall_entry) ( UInt sysno );
+
+#else
+# error Unknown OS
+#endif
/* ---------------------------------------------------------------------
Declaring and defining wrappers.
[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. */
#define GENX_(sysno, name) WRAPPER_ENTRY_X_(generic, sysno, name)
#define GENXY(sysno, name) WRAPPER_ENTRY_XY(generic, sysno, name)
#define LINX_(sysno, name) WRAPPER_ENTRY_X_(linux, sysno, name)
#define LINXY(sysno, name) WRAPPER_ENTRY_XY(linux, sysno, name)
+/* Add an AIX5-specific, arch-independent wrapper to a syscall
+ table. */
+#define AIXXY(sysno, name) \
+ { & sysno, \
+ { & WRAPPER_PRE_NAME(aix5, name), \
+ & WRAPPER_POST_NAME(aix5, name) }}
+
+#define AIXX_(sysno, name) \
+ { & sysno, \
+ { & WRAPPER_PRE_NAME(aix5, name), \
+ NULL }}
/* ---------------------------------------------------------------------
#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. Note that
-
- (1) status->val by itself is meaningless -- you have to consider it
- together with status->what, which is why RES uses a helper
- function (this also has the desirable effect of turning RES
- into a non-lvalue).
-
- (2) post-wrappers will not get called in case of failure (unless
- PostOnFail is set, which is rare). This is why the assertion
- in getRES is viable.
-
- If you really really want to just get hold of status->val without
- inspecting status->what, use RES_unchecked. This is dangerous and
- therefore discouraged.
-*/
-#define SUCCESS (status->what == SsSuccess)
-#define FAILURE (status->what == SsFailure)
+/* Reference to the syscall's current result status/value. General
+ paranoia all round. */
+#define SUCCESS (status->what == SsComplete && !status->sres.isError)
+#define FAILURE (status->what == SsComplete && status->sres.isError)
#define SWHAT (status->what)
-#define RES_unchecked (status->val) /* do not use! */
-#define RES (getRES(status)) /* use this instead, if possible */
+#define RES (getRES(status))
+#define ERR (getERR(status))
static inline UWord getRES ( SyscallStatus* st ) {
- vg_assert(st->what == SsSuccess);
- return st->val;
+ vg_assert(st->what == SsComplete);
+ vg_assert(!st->sres.isError);
+ return st->sres.res;
}
+static inline UWord getERR ( SyscallStatus* st ) {
+ vg_assert(st->what == SsComplete);
+ vg_assert(st->sres.isError);
+ return st->sres.err;
+}
/* Set the current result status/value in various ways. */
#define SET_STATUS_Success(zzz) \
- do { status->what = SsSuccess; \
- status->val = (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 = SsFailure; \
- status->val = wzz; \
+ status->what = SsComplete; \
+ status->sres = VG_(mk_SysRes_Error)(wzz); \
} while (0)
#define SET_STATUS_from_SysRes(zzz) \
do { \
- SysRes zres = (zzz); \
- if (zres.isError) { \
- SET_STATUS_Failure(zres.val); \
- } else { \
- SET_STATUS_Success(zres.val); \
- } \
+ status->what = SsComplete; \
+ status->sres = (zzz); \
} while (0)
/* A lamentable kludge */
status->val = wzz; \
} while (0)
-#define SET_STATUS_from_SysRes_NO_SANITY_CHECK(zzz) \
- do { \
- SysRes zres = (zzz); \
- if (zres.isError) { \
- SET_STATUS_Failure_NO_SANITY_CHECK(zres.val); \
- } else { \
- SET_STATUS_Success(zres.val); \
- } \
- } while (0)
-
#define PRINT(format, args...) \
if (VG_(clo_trace_syscalls)) \
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) \
*/
#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) \
# define MIN_SIZET(_aa,_bb) (_aa) < (_bb) ? (_aa) : (_bb)
Bool ok, d;
- NSegment* old_seg;
+ NSegment const* old_seg;
Addr advised;
Bool f_fixed = toBool(flags & VKI_MREMAP_FIXED);
Bool f_maymove = toBool(flags & VKI_MREMAP_MAYMOVE);
the next segment along. So make very sure that the proposed
new area really is free. This is perhaps overly
conservative, but it fixes #129866. */
- NSegment* segLo = VG_(am_find_nsegment)( needA );
- NSegment* segHi = VG_(am_find_nsegment)( needA + needL - 1 );
+ NSegment const* segLo = VG_(am_find_nsegment)( needA );
+ NSegment const* segHi = VG_(am_find_nsegment)( needA + needL - 1 );
if (segLo == NULL || segHi == NULL
|| segLo != segHi || segLo->kind != SkFree)
ok = False;
}
if (ok && advised == needA) {
- ok = VG_(am_extend_map_client)( &d, old_seg, needL );
+ ok = VG_(am_extend_map_client)( &d, (NSegment*)old_seg, needL );
if (ok) {
VG_TRACK( new_mem_mmap, needA, needL,
old_seg->hasR,
this-or-nothing) is too lenient, and may allow us to trash
the next segment along. So make very sure that the proposed
new area really is free. */
- NSegment* segLo = VG_(am_find_nsegment)( needA );
- NSegment* segHi = VG_(am_find_nsegment)( needA + needL - 1 );
+ NSegment const* segLo = VG_(am_find_nsegment)( needA );
+ NSegment const* segHi = VG_(am_find_nsegment)( needA + needL - 1 );
if (segLo == NULL || segHi == NULL
|| segLo != segHi || segLo->kind != SkFree)
ok = False;
}
if (!ok || advised != needA)
goto eNOMEM;
- ok = VG_(am_extend_map_client)( &d, old_seg, needL );
+ ok = VG_(am_extend_map_client)( &d, (NSegment*)old_seg, needL );
if (!ok)
goto eNOMEM;
VG_TRACK( new_mem_mmap, needA, needL,
return;
}
- while ((ret = VG_(getdents)(f.val, &d, sizeof(d))) != 0) {
+ while ((ret = VG_(getdents)(f.res, &d, sizeof(d))) != 0) {
if (ret == -1)
goto out;
if (VG_(strcmp)(d.d_name, ".") && VG_(strcmp)(d.d_name, "..")) {
Int fno = VG_(atoll)(d.d_name);
- if (fno != f.val)
+ if (fno != f.res)
if (VG_(clo_track_fds))
record_fd_open_named(-1, fno);
}
- VG_(lseek)(f.val, d.d_off, VKI_SEEK_SET);
+ VG_(lseek)(f.res, d.d_off, VKI_SEEK_SET);
}
out:
- VG_(close)(f.val);
+ VG_(close)(f.res);
}
static
static Addr do_brk ( Addr newbrk )
{
- NSegment *aseg, *rseg;
+ NSegment const* aseg;
+ NSegment const* rseg;
Addr newbrkP;
SizeT delta;
Bool ok;
if (newbrk >= VG_(brk_base) && newbrk < VG_(brk_limit)) {
/* shrinking the data segment. Be lazy and don't munmap the
excess area. */
- NSegment* seg = VG_(am_find_nsegment)(newbrk);
+ NSegment const * seg = VG_(am_find_nsegment)(newbrk);
if (seg && seg->hasT)
VG_(discard_translations)( newbrk, VG_(brk_limit) - newbrk,
"do_brk(shrink)" );
if (seg) {
/* pre: newbrk < VG_(brk_limit)
=> newbrk <= VG_(brk_limit)-1 */
- NSegment* seg2;
+ NSegment const * seg2;
vg_assert(newbrk < VG_(brk_limit));
seg2 = VG_(am_find_nsegment)( VG_(brk_limit)-1 );
if (seg2 && seg == seg2 && seg->hasW)
aseg = VG_(am_find_nsegment)( VG_(brk_limit)-1 );
else
aseg = VG_(am_find_nsegment)( VG_(brk_limit) );
- rseg = VG_(am_next_nsegment)( aseg, True/*forwards*/ );
+ rseg = VG_(am_next_nsegment)( (NSegment*)aseg, True/*forwards*/ );
/* These should be assured by setup_client_dataseg in m_main. */
vg_assert(aseg);
vg_assert(delta > 0);
vg_assert(VG_IS_PAGE_ALIGNED(delta));
- ok = VG_(am_extend_into_adjacent_reservation_client)( aseg, delta );
+ ok = VG_(am_extend_into_adjacent_reservation_client)( (NSegment*)aseg, delta );
if (!ok) goto bad;
VG_(brk_limit) = newbrk;
{
SysRes r = res;
vg_assert(!res.isError); /* guaranteed by caller */
- if (!ML_(fd_allowed)(res.val, "socket", tid, True)) {
- VG_(close)(res.val);
+ if (!ML_(fd_allowed)(res.res, "socket", tid, True)) {
+ VG_(close)(res.res);
r = VG_(mk_SysRes_Error)( VKI_EMFILE );
} else {
if (VG_(clo_track_fds))
- ML_(record_fd_open_nameless)(tid, res.val);
+ ML_(record_fd_open_nameless)(tid, res.res);
}
return r;
}
{
SysRes r = res;
vg_assert(!res.isError); /* guaranteed by caller */
- if (!ML_(fd_allowed)(res.val, "accept", tid, True)) {
- VG_(close)(res.val);
+ if (!ML_(fd_allowed)(res.res, "accept", tid, True)) {
+ VG_(close)(res.res);
r = VG_(mk_SysRes_Error)( VKI_EMFILE );
} else {
Addr addr_p = arg1;
buf_and_len_post_check ( tid, res, addr_p, addrlen_p,
"socketcall.accept(addrlen_out)" );
if (VG_(clo_track_fds))
- ML_(record_fd_open_nameless)(tid, res.val);
+ ML_(record_fd_open_nameless)(tid, res.res);
}
return r;
}
void
ML_(generic_POST_sys_shmdt) ( ThreadId tid, UWord res, UWord arg0 )
{
- NSegment* s = VG_(am_find_nsegment)(arg0);
+ NSegment const* s = VG_(am_find_nsegment)(arg0);
if (s != NULL) {
Addr s_start = s->start;
if (!sres.isError) {
/* Notify aspacem and the tool. */
ML_(notify_aspacem_and_tool_of_mmap)(
- (Addr)sres.val, /* addr kernel actually assigned */
+ (Addr)sres.res, /* addr kernel actually assigned */
arg2, arg3,
arg4, /* the original flags value */
arg5, arg6
);
/* Load symbols? */
- VG_(di_notify_mmap)( (Addr)sres.val, False/*allow_SkFileV*/ );
+ VG_(di_notify_mmap)( (Addr)sres.res, False/*allow_SkFileV*/ );
}
/* Stay sane */
if (!sres.isError && (arg4 & VKI_MAP_FIXED))
- vg_assert(sres.val == arg1);
+ vg_assert(sres.res == arg1);
return sres;
}
tst = VG_(get_ThreadState)(tid);
/* Set the thread's status to be exiting, then claim that the
syscall succeeded. */
- tst->exitreason = VgSrc_ExitSyscall;
+ tst->exitreason = VgSrc_ExitThread;
tst->os_state.exitcode = ARG1;
SET_STATUS_Success(0);
}
// ok, etc.
res = VG_(pre_exec_check)((const Char*)ARG1, NULL);
if (res.isError) {
- SET_STATUS_Failure( res.val );
+ SET_STATUS_Failure( res.res );
return;
}
/* Resistance is futile. Nuke all other threads. POSIX mandates
this. (Really, nuke them all, since the new process will make
its own new thread.) */
- VG_(nuke_all_threads_except)( tid, VgSrc_ExitSyscall );
+ VG_(nuke_all_threads_except)( tid, VgSrc_ExitThread );
VG_(reap_threads)(tid);
// Set up the child's exe path.
{
vki_sigset_t allsigs;
vki_siginfo_t info;
- static const struct vki_timespec zero = { 0, 0 };
for (i = 1; i < VG_(max_signal); i++) {
struct vki_sigaction sa;
}
VG_(sigfillset)(&allsigs);
- while(VG_(sigtimedwait)(&allsigs, &info, &zero) > 0)
+ while(VG_(sigtimedwait_zero)(&allsigs, &info) > 0)
;
VG_(sigprocmask)(VKI_SIG_SETMASK, &tst->sig_mask, NULL);
hosed:
vg_assert(FAILURE);
VG_(message)(Vg_UserMsg, "execve(%p(%s), %p, %p) failed, errno %d",
- ARG1, ARG1, ARG2, ARG3, RES_unchecked);
+ ARG1, ARG1, ARG2, ARG3, ERR);
VG_(message)(Vg_UserMsg, "EXEC FAILED: I can't recover from "
"execve() failing, so I'm dying.");
VG_(message)(Vg_UserMsg, "Add more stringent tests in PRE(sys_execve), "
tst->os_state.fatalsig = VKI_SIGKILL;
if (!VG_(is_running_thread)(tid))
- VG_(kill_thread)(tid);
+ VG_(get_thread_out_of_syscall)(tid);
}
return True;
The sanity check provided by the kernel is that the vma must
have the VM_GROWSDOWN/VM_GROWSUP flag set as appropriate. */
UInt grows = ARG3 & (VKI_PROT_GROWSDOWN|VKI_PROT_GROWSUP);
- NSegment *aseg = VG_(am_find_nsegment)(ARG1);
- NSegment *rseg;
+ NSegment const *aseg = VG_(am_find_nsegment)(ARG1);
+ NSegment const *rseg;
vg_assert(aseg);
if (grows == VKI_PROT_GROWSDOWN) {
- rseg = VG_(am_next_nsegment)( aseg, False/*backwards*/ );
+ rseg = VG_(am_next_nsegment)( (NSegment*)aseg, False/*backwards*/ );
if (rseg &&
rseg->kind == SkResvn &&
rseg->smode == SmUpper &&
SET_STATUS_Failure( VKI_EINVAL );
}
} else if (grows == VKI_PROT_GROWSUP) {
- rseg = VG_(am_next_nsegment)( aseg, True/*forwards*/ );
+ rseg = VG_(am_next_nsegment)( (NSegment*)aseg, True/*forwards*/ );
if (rseg &&
rseg->kind == SkResvn &&
rseg->smode == SmLower &&
POST(sys_nanosleep)
{
vg_assert(SUCCESS || FAILURE);
- if (ARG2 != 0 && FAILURE && RES_unchecked == VKI_EINTR)
+ if (ARG2 != 0 && FAILURE && ERR == VKI_EINTR)
POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec) );
}
sres = VG_(dup)( VG_(cl_cmdline_fd) );
SET_STATUS_from_SysRes( sres );
if (!sres.isError) {
- OffT off = VG_(lseek)( sres.val, 0, VKI_SEEK_SET );
+ OffT off = VG_(lseek)( sres.res, 0, VKI_SEEK_SET );
if (off < 0)
SET_STATUS_Failure( VKI_EMFILE );
}
#include "libvex_guest_offsets.h"
#include "pub_core_basics.h"
#include "pub_core_vki.h"
-#include "pub_core_basics.h"
+#include "pub_core_vkiscnums.h"
#include "pub_core_threadstate.h"
#include "pub_core_libcbase.h"
#include "pub_core_libcassert.h"
/* Useful info which needs to be recorded somewhere:
- Use of registers in syscalls (on linux) is:
-
- NUM ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 RESULT
- x86 eax ebx ecx edx esi edi ebp eax (== NUM)
- amd64 rax rdi rsi rdx r10 r8 r9 rax (== NUM)
- ppc32 r0 r3 r4 r5 r6 r7 r8 r3+CR0.SO (== ARG1)
- ppc64 r0 r3 r4 r5 r6 r7 r8 r3+CR0.SO (== ARG1)
+ Use of registers in syscalls is:
+
+ NUM ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7 ARG8 RESULT
+ LINUX:
+ x86 eax ebx ecx edx esi edi ebp n/a n/a eax (== NUM)
+ amd64 rax rdi rsi rdx r10 r8 r9 n/a n/a rax (== NUM)
+ ppc32 r0 r3 r4 r5 r6 r7 r8 n/a n/a r3+CR0.SO (== ARG1)
+ ppc64 r0 r3 r4 r5 r6 r7 r8 n/a n/a r3+CR0.SO (== ARG1)
+ AIX:
+ ppc32 r2 r3 r4 r5 r6 r7 r8 r9 r10 r3(res),r4(err)
+ ppc64 r2 r3 r4 r5 r6 r7 r8 r9 r10 r3(res),r4(err)
*/
/* This is the top level of the system-call handler module. All
VG_(fixup_guest_state_after_syscall_interrupted) below for details.
*/
extern
-UWord ML_(do_syscall_for_client_WRK)( Int syscallno,
+UWord ML_(do_syscall_for_client_WRK)( Word syscallno,
void* guest_state,
const vki_sigset_t *syscall_mask,
const vki_sigset_t *restore_mask,
- Int nsigwords );
+ Word nsigwords
+# if defined(VGO_aix5)
+ , Word __nr_sigprocmask
+# endif
+ );
static
void do_syscall_for_client ( Int syscallno,
= ML_(do_syscall_for_client_WRK)(
syscallno, &tst->arch.vex,
syscall_mask, &saved, _VKI_NSIG_WORDS * sizeof(UWord)
+# if defined(VGO_aix5)
+ , __NR_rt_sigprocmask
+# endif
);
vg_assert2(
err == 0,
&& a1->arg3 == a2->arg3
&& a1->arg4 == a2->arg4
&& a1->arg5 == a2->arg5
- && a1->arg6 == a2->arg6;
+ && a1->arg6 == a2->arg6
+ && a1->arg7 == a2->arg7
+ && a1->arg8 == a2->arg8;
}
static
Bool eq_SyscallStatus ( SyscallStatus* s1, SyscallStatus* s2 )
{
return s1->what == s2->what
- && s1->val == s2->val;
+ && s1->sres.res == s2->sres.res
+ && s1->sres.err == s2->sres.err;
}
-/* Convert between SysRet and SyscallStatus, to the extent possible. */
-
-/* This is unused. */
-/*
-static
-SysRes convert_SyscallStatus_to_SysRes ( SyscallStatus status )
-{
- SysRes res;
- vg_assert(status.what == SsSuccess || status.what == SsFailure);
- res.isError = status.what == SsFailure;
- res.val = status.val;
- return res;
-}
-*/
+/* Convert between SysRes and SyscallStatus, to the extent possible. */
static
SyscallStatus convert_SysRes_to_SyscallStatus ( SysRes res )
{
SyscallStatus status;
- status.what = res.isError ? SsFailure : SsSuccess;
- status.val = res.val;
+ status.what = SsComplete;
+ status.sres = res;
return status;
}
canonical->arg4 = gst->guest_ESI;
canonical->arg5 = gst->guest_EDI;
canonical->arg6 = gst->guest_EBP;
+ canonical->arg7 = 0;
+ canonical->arg8 = 0;
#elif defined(VGP_amd64_linux)
VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
canonical->arg4 = gst->guest_R10;
canonical->arg5 = gst->guest_R8;
canonical->arg6 = gst->guest_R9;
+ canonical->arg7 = 0;
+ canonical->arg8 = 0;
+
#elif defined(VGP_ppc32_linux)
VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
canonical->arg4 = gst->guest_GPR6;
canonical->arg5 = gst->guest_GPR7;
canonical->arg6 = gst->guest_GPR8;
+ canonical->arg7 = 0;
+ canonical->arg8 = 0;
+
#elif defined(VGP_ppc64_linux)
VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
canonical->arg4 = gst->guest_GPR6;
canonical->arg5 = gst->guest_GPR7;
canonical->arg6 = gst->guest_GPR8;
+ canonical->arg7 = 0;
+ canonical->arg8 = 0;
+
+
+#elif defined(VGP_ppc32_aix5)
+ VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
+ canonical->sysno = gst->guest_GPR2;
+ canonical->arg1 = gst->guest_GPR3;
+ canonical->arg2 = gst->guest_GPR4;
+ canonical->arg3 = gst->guest_GPR5;
+ canonical->arg4 = gst->guest_GPR6;
+ canonical->arg5 = gst->guest_GPR7;
+ canonical->arg6 = gst->guest_GPR8;
+ canonical->arg7 = gst->guest_GPR9;
+ canonical->arg8 = gst->guest_GPR10;
+
+#elif defined(VGP_ppc64_aix5)
+ VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
+ canonical->sysno = gst->guest_GPR2;
+ canonical->arg1 = gst->guest_GPR3;
+ canonical->arg2 = gst->guest_GPR4;
+ canonical->arg3 = gst->guest_GPR5;
+ canonical->arg4 = gst->guest_GPR6;
+ canonical->arg5 = gst->guest_GPR7;
+ canonical->arg6 = gst->guest_GPR8;
+ canonical->arg7 = gst->guest_GPR9;
+ canonical->arg8 = gst->guest_GPR10;
#else
# error "getSyscallArgsFromGuestState: unknown arch"
gst->guest_GPR7 = canonical->arg5;
gst->guest_GPR8 = canonical->arg6;
+#elif defined(VGP_ppc32_aix5)
+ VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
+ gst->guest_GPR2 = canonical->sysno;
+ gst->guest_GPR3 = canonical->arg1;
+ gst->guest_GPR4 = canonical->arg2;
+ gst->guest_GPR5 = canonical->arg3;
+ gst->guest_GPR6 = canonical->arg4;
+ gst->guest_GPR7 = canonical->arg5;
+ gst->guest_GPR8 = canonical->arg6;
+ gst->guest_GPR9 = canonical->arg7;
+ gst->guest_GPR10 = canonical->arg8;
+
+#elif defined(VGP_ppc64_aix5)
+ VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
+ gst->guest_GPR2 = canonical->sysno;
+ gst->guest_GPR3 = canonical->arg1;
+ gst->guest_GPR4 = canonical->arg2;
+ gst->guest_GPR5 = canonical->arg3;
+ gst->guest_GPR6 = canonical->arg4;
+ gst->guest_GPR7 = canonical->arg5;
+ gst->guest_GPR8 = canonical->arg6;
+ gst->guest_GPR9 = canonical->arg7;
+ gst->guest_GPR10 = canonical->arg8;
+
#else
# error "putSyscallArgsIntoGuestState: unknown arch"
#endif
void getSyscallStatusFromGuestState ( /*OUT*/SyscallStatus* canonical,
/*IN*/ VexGuestArchState* gst_vanilla )
{
-#if defined(VGP_x86_linux)
+# if defined(VGP_x86_linux)
VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
- Int i = (Int)gst->guest_EAX;
- canonical->what = i >= -4095 && i <= -1 ? SsFailure : SsSuccess;
- canonical->val = (UWord)(canonical->what==SsFailure ? -i : i);
+ canonical->sres = VG_(mk_SysRes_x86_linux)( gst->guest_EAX );
+ canonical->what = SsComplete;
-#elif defined(VGP_amd64_linux)
+# elif defined(VGP_amd64_linux)
VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
- Long i = (Long)gst->guest_RAX;
- canonical->what = i >= -4095 && i <= -1 ? SsFailure : SsSuccess;
- canonical->val = (UWord)(canonical->what==SsFailure ? -i : i);
-
-#elif defined(VGP_ppc32_linux)
+ canonical->sres = VG_(mk_SysRes_amd64_linux)( gst->guest_RAX );
+ canonical->what = SsComplete;
+
+# elif defined(VGP_ppc32_linux)
+ VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
+ UInt cr = LibVEX_GuestPPC32_get_CR( gst );
+ UInt cr0so = (cr >> 28) & 1;
+ canonical->sres = VG_(mk_SysRes_ppc32_linux)( gst->guest_GPR3, cr0so );
+ canonical->what = SsComplete;
+
+# elif defined(VGP_ppc64_linux)
+ VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
+ UInt cr = LibVEX_GuestPPC64_get_CR( gst );
+ UInt cr0so = (cr >> 28) & 1;
+ canonical->sres = VG_(mk_SysRes_ppc64_linux)( gst->guest_GPR3, cr0so );
+ canonical->what = SsComplete;
+
+# elif defined(VGP_ppc32_aix5)
VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
- UInt cr = LibVEX_GuestPPC32_get_CR( gst );
- UInt err = (cr >> 28) & 1; // CR0.SO
- canonical->what = (err == 1) ? SsFailure : SsSuccess;
- canonical->val = (UWord)gst->guest_GPR3;
+ canonical->sres = VG_(mk_SysRes_ppc32_aix5)( gst->guest_GPR3,
+ gst->guest_GPR4 );
+ canonical->what = SsComplete;
-#elif defined(VGP_ppc64_linux)
+# elif defined(VGP_ppc64_aix5)
VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
- UInt cr = LibVEX_GuestPPC64_get_CR( gst );
- UInt err = (cr >> 28) & 1; // CR0.SO
- canonical->what = (err == 1) ? SsFailure : SsSuccess;
- canonical->val = (UWord)gst->guest_GPR3;
+ canonical->sres = VG_(mk_SysRes_ppc64_aix5)( gst->guest_GPR3,
+ gst->guest_GPR4 );
+ canonical->what = SsComplete;
-#else
-# error "getSyscallStatusFromGuestState: unknown arch"
-#endif
+# else
+# error "getSyscallStatusFromGuestState: unknown arch"
+# endif
}
static
void putSyscallStatusIntoGuestState ( /*IN*/ SyscallStatus* canonical,
/*OUT*/VexGuestArchState* gst_vanilla )
{
-#if defined(VGP_x86_linux)
+# if defined(VGP_x86_linux)
VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
- vg_assert(canonical->what == SsSuccess
- || canonical->what == SsFailure);
- if (canonical->what == SsFailure) {
+ vg_assert(canonical->what == SsComplete);
+ if (canonical->sres.isError) {
/* This isn't exactly right, in that really a Failure with res
not in the range 1 .. 4095 is unrepresentable in the
Linux-x86 scheme. Oh well. */
- gst->guest_EAX = - (Int)canonical->val;
+ gst->guest_EAX = - (Int)canonical->sres.err;
} else {
- gst->guest_EAX = canonical->val;
+ gst->guest_EAX = canonical->sres.res;
}
-#elif defined(VGP_amd64_linux)
+
+# elif defined(VGP_amd64_linux)
VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
- vg_assert(canonical->what == SsSuccess
- || canonical->what == SsFailure);
- if (canonical->what == SsFailure) {
+ vg_assert(canonical->what == SsComplete);
+ if (canonical->sres.isError) {
/* This isn't exactly right, in that really a Failure with res
not in the range 1 .. 4095 is unrepresentable in the
Linux-x86 scheme. Oh well. */
- gst->guest_RAX = - (Long)canonical->val;
+ gst->guest_RAX = - (Long)canonical->sres.err;
} else {
- gst->guest_RAX = canonical->val;
+ gst->guest_RAX = canonical->sres.res;
}
-#elif defined(VGP_ppc32_linux)
+# elif defined(VGP_ppc32_linux)
VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
UInt old_cr = LibVEX_GuestPPC32_get_CR(gst);
-
- vg_assert(canonical->what == SsSuccess
- || canonical->what == SsFailure);
-
- gst->guest_GPR3 = canonical->val;
-
- if (canonical->what == SsFailure) {
+ vg_assert(canonical->what == SsComplete);
+ if (canonical->sres.isError) {
/* set CR0.SO */
LibVEX_GuestPPC32_put_CR( old_cr | (1<<28), gst );
+ gst->guest_GPR3 = canonical->sres.err;
} else {
/* clear CR0.SO */
LibVEX_GuestPPC32_put_CR( old_cr & ~(1<<28), gst );
+ gst->guest_GPR3 = canonical->sres.res;
}
-#elif defined(VGP_ppc64_linux)
+# elif defined(VGP_ppc64_linux)
VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
UInt old_cr = LibVEX_GuestPPC64_get_CR(gst);
-
- vg_assert(canonical->what == SsSuccess
- || canonical->what == SsFailure);
-
- gst->guest_GPR3 = canonical->val;
-
- if (canonical->what == SsFailure) {
+ vg_assert(canonical->what == SsComplete);
+ if (canonical->sres.isError) {
/* set CR0.SO */
LibVEX_GuestPPC64_put_CR( old_cr | (1<<28), gst );
+ gst->guest_GPR3 = canonical->sres.err;
} else {
/* clear CR0.SO */
LibVEX_GuestPPC64_put_CR( old_cr & ~(1<<28), gst );
+ gst->guest_GPR3 = canonical->sres.res;
}
-#else
-# error "putSyscallStatusIntoGuestState: unknown arch"
-#endif
+# elif defined(VGP_ppc32_aix5)
+ VexGuestPPC32State* gst = (VexGuestPPC32State*)gst_vanilla;
+ vg_assert(canonical->what == SsComplete);
+ gst->guest_GPR3 = canonical->sres.res;
+ gst->guest_GPR4 = canonical->sres.err;
+
+# elif defined(VGP_ppc64_aix5)
+ VexGuestPPC64State* gst = (VexGuestPPC64State*)gst_vanilla;
+ vg_assert(canonical->what == SsComplete);
+ gst->guest_GPR3 = canonical->sres.res;
+ gst->guest_GPR4 = canonical->sres.err;
+
+# else
+# error "putSyscallStatusIntoGuestState: unknown arch"
+# endif
}
layout->o_arg4 = OFFSET_x86_ESI;
layout->o_arg5 = OFFSET_x86_EDI;
layout->o_arg6 = OFFSET_x86_EBP;
+ layout->o_arg7 = -1; /* impossible value */
+ layout->o_arg8 = -1; /* impossible value */
layout->o_retval = OFFSET_x86_EAX;
#elif defined(VGP_amd64_linux)
layout->o_arg4 = OFFSET_amd64_R10;
layout->o_arg5 = OFFSET_amd64_R8;
layout->o_arg6 = OFFSET_amd64_R9;
+ layout->o_arg7 = -1; /* impossible value */
+ layout->o_arg8 = -1; /* impossible value */
layout->o_retval = OFFSET_amd64_RAX;
#elif defined(VGP_ppc32_linux)
layout->o_arg4 = OFFSET_ppc32_GPR6;
layout->o_arg5 = OFFSET_ppc32_GPR7;
layout->o_arg6 = OFFSET_ppc32_GPR8;
+ layout->o_arg7 = -1; /* impossible value */
+ layout->o_arg8 = -1; /* impossible value */
layout->o_retval = OFFSET_ppc32_GPR3;
#elif defined(VGP_ppc64_linux)
layout->o_arg4 = OFFSET_ppc64_GPR6;
layout->o_arg5 = OFFSET_ppc64_GPR7;
layout->o_arg6 = OFFSET_ppc64_GPR8;
+ layout->o_arg7 = -1; /* impossible value */
+ layout->o_arg8 = -1; /* impossible value */
+ layout->o_retval = OFFSET_ppc64_GPR3;
+
+#elif defined(VGP_ppc32_aix5)
+ layout->o_sysno = OFFSET_ppc32_GPR2;
+ layout->o_arg1 = OFFSET_ppc32_GPR3;
+ layout->o_arg2 = OFFSET_ppc32_GPR4;
+ layout->o_arg3 = OFFSET_ppc32_GPR5;
+ layout->o_arg4 = OFFSET_ppc32_GPR6;
+ layout->o_arg5 = OFFSET_ppc32_GPR7;
+ layout->o_arg6 = OFFSET_ppc32_GPR8;
+ layout->o_arg7 = OFFSET_ppc32_GPR9;
+ layout->o_arg8 = OFFSET_ppc32_GPR10;
+ layout->o_retval = OFFSET_ppc32_GPR3;
+
+#elif defined(VGP_ppc64_aix5)
+ layout->o_sysno = OFFSET_ppc64_GPR2;
+ layout->o_arg1 = OFFSET_ppc64_GPR3;
+ layout->o_arg2 = OFFSET_ppc64_GPR4;
+ layout->o_arg3 = OFFSET_ppc64_GPR5;
+ layout->o_arg4 = OFFSET_ppc64_GPR6;
+ layout->o_arg5 = OFFSET_ppc64_GPR7;
+ layout->o_arg6 = OFFSET_ppc64_GPR8;
+ layout->o_arg7 = OFFSET_ppc64_GPR9;
+ layout->o_arg8 = OFFSET_ppc64_GPR10;
layout->o_retval = OFFSET_ppc64_GPR3;
#else
static const SyscallTableEntry* get_syscall_entry ( UInt syscallno )
{
- const SyscallTableEntry* sys = &bad_sys;
+ const SyscallTableEntry* sys = NULL;
+# if defined(VGO_linux)
if (syscallno < ML_(syscall_table_size) &&
ML_(syscall_table)[syscallno].before != NULL)
sys = &ML_(syscall_table)[syscallno];
- return sys;
+# elif defined(VGP_ppc32_aix5)
+ sys = ML_(get_ppc32_aix5_syscall_entry) ( syscallno );
+
+# elif defined(VGP_ppc64_aix5)
+ sys = ML_(get_ppc64_aix5_syscall_entry) ( syscallno );
+
+# else
+# error Unknown OS
+# endif
+
+ return sys == NULL ? &bad_sys : sys;
}
sysno = sci->orig_args.sysno;
/* The default what-to-do-next thing is hand the syscall to the
- kernel, so we pre-set that here. */
+ kernel, so we pre-set that here. Set .sres to something
+ harmless looking (is irrelevant because .what is not
+ SsComplete.) */
sci->status.what = SsHandToKernel;
- sci->status.val = 0;
+ sci->status.sres = VG_(mk_SysRes_Error)(0);
sci->flags = 0;
/* Fetch the syscall's handlers. If no handlers exist for this
*/
/* Now we proceed according to what the pre-handler decided. */
vg_assert(sci->status.what == SsHandToKernel
- || sci->status.what == SsSuccess
- || sci->status.what == SsFailure);
+ || sci->status.what == SsComplete);
vg_assert(sci->args.sysno == sci->orig_args.sysno);
- if (sci->status.what == SsSuccess) {
+ if (sci->status.what == SsComplete && !sci->status.sres.isError) {
/* The pre-handler completed the syscall itself, declaring
success. */
- PRINT(" --> [pre-success] Success(0x%llx)\n", (Long)sci->status.val );
+ PRINT(" --> [pre-success] Success(0x%llx)\n", (ULong)sci->status.sres.res );
/* In this case the allowable flags are to ask for a signal-poll
and/or a yield after the call. Changing the args isn't
}
else
- if (sci->status.what == SsFailure) {
+ if (sci->status.what == SsComplete && sci->status.sres.isError) {
/* The pre-handler decided to fail syscall itself. */
- PRINT(" --> [pre-fail] Failure(0x%llx)\n", (Long)sci->status.val );
+ PRINT(" --> [pre-fail] Failure(0x%llx)\n", (ULong)sci->status.sres.err );
/* In this case, the pre-handler is also allowed to ask for the
post-handler to be run anyway. Changing the args is not
allowed. */
putSyscallArgsIntoGuestState( &sci->args, &tst->arch.vex );
/* Drop the lock */
- VG_(set_sleeping)(tid, VgTs_WaitSys);
+ VG_(set_sleeping)(tid, VgTs_WaitSys, "VG_(client_syscall)[async]");
/* Do the call, which operates directly on the guest state,
not on our abstracted copies of the args/result. */
to the scheduler. */
/* Reacquire the lock */
- VG_(set_running)(tid);
+ VG_(set_running)(tid, "VG_(client_syscall)[async]");
/* Even more impedance matching. Extract the syscall status
from the guest state. */
getSyscallStatusFromGuestState( &sci->status, &tst->arch.vex );
+ vg_assert(sci->status.what == SsComplete);
PRINT("SYSCALL[%d,%d](%3d) ... [async] --> %s(0x%llx)\n",
VG_(getpid)(), tid, sysno,
- sci->status.what==SsSuccess ? "Success" : "Failure",
- (Long)sci->status.val );
+ sci->status.sres.isError ? "Failure" : "Success",
+ sci->status.sres.isError ? (ULong)sci->status.sres.err
+ : (ULong)sci->status.sres.res );
} else {
kernel, there's no point in flushing them back to the
guest state. Indeed doing so could be construed as
incorrect. */
-
SysRes sres
- = VG_(do_syscall6)(sysno, sci->args.arg1, sci->args.arg2,
- sci->args.arg3, sci->args.arg4,
- sci->args.arg5, sci->args.arg6 );
+ = VG_(do_syscall)(sysno, sci->args.arg1, sci->args.arg2,
+ sci->args.arg3, sci->args.arg4,
+ sci->args.arg5, sci->args.arg6,
+ sci->args.arg7, sci->args.arg8 );
sci->status = convert_SysRes_to_SyscallStatus(sres);
PRINT("[sync] --> %s(0x%llx)\n",
- sci->status.what==SsSuccess ? "Success" : "Failure",
- (Long)sci->status.val );
+ sci->status.sres.isError ? "Failure" : "Success",
+ sci->status.sres.isError ? (ULong)sci->status.sres.err
+ : (ULong)sci->status.sres.res );
}
}
- vg_assert(sci->status.what == SsFailure
- || sci->status.what == SsSuccess);
+ vg_assert(sci->status.what == SsComplete);
vg_assert(VG_(is_running_thread)(tid));
/* Validate current syscallInfo entry. In particular we require
that the current .status matches what's actually in the guest
state. */
- vg_assert(sci->status.what == SsFailure
- || sci->status.what == SsSuccess);
+ vg_assert(sci->status.what == SsComplete);
getSyscallStatusFromGuestState( &test_status, &tst->arch.vex );
vg_assert(eq_SyscallStatus( &sci->status, &test_status ));
VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, layout.o_retval,
sizeof(UWord) );
- /* Consider, either success or failure. Now run the post handler if:
+ /* pre: status == Complete (asserted above) */
+ /* Consider either success or failure. Now run the post handler if:
- it exists, and
- - status==Success or (status==Fail and PostOnFail is set)
+ - Success or (Failure and PostOnFail is set)
*/
if (ent->after
- && (sci->status.what == SsSuccess
- || (sci->status.what == SsFailure
+ && ((!sci->status.sres.isError)
+ || (sci->status.sres.isError
&& (sci->flags & SfPostOnFail) ))) {
(ent->after)( tid, &sci->args, &sci->status );
putSyscallStatusIntoGuestState( &sci->status, &tst->arch.vex );
/* Do any post-syscall actions required by the tool. */
- if (VG_(needs).syscall_wrapper) {
- SysRes res;
- res.val = sci->status.val;
- res.isError = sci->status.what == SsFailure;
- VG_TDICT_CALL(tool_post_syscall, tid, sysno, res);
- }
+ if (VG_(needs).syscall_wrapper)
+ VG_TDICT_CALL(tool_post_syscall, tid, sysno, sci->status.sres);
/* The syscall is done. */
+ vg_assert(sci->status.what == SsComplete);
sci->status.what = SsIdle;
/* The pre/post wrappers may have concluded that pending signals
vg_assert(p[0] == 0x44 && p[1] == 0x0 && p[2] == 0x0 && p[3] == 0x2);
}
+#elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
+ /* Hmm. This is problematic, because on AIX the kernel resumes
+ after a syscall at LR, not at the insn following SC. Hence
+ there is no obvious way to figure out where the SC is. Current
+ solution is to have a pseudo-register in the guest state,
+ CIA_AT_SC, which holds the address of the most recent SC
+ executed. Backing up to that syscall then simply involves
+ copying that value back into CIA (the program counter). */
+ arch->vex.guest_CIA = arch->vex.guest_CIA_AT_SC;
+
+ /* Make sure our caller is actually sane, and we're really backing
+ back over a syscall.
+
+ sc == 44 00 00 02
+ */
+ {
+ UChar *p = (UChar *)arch->vex.guest_CIA;
+
+ if (p[0] != 0x44 || p[1] != 0x0 || p[2] != 0x0 || p[3] != 0x02)
+ VG_(message)(Vg_DebugMsg,
+ "?! restarting over syscall at %p %02x %02x %02x %02x\n",
+ arch->vex.guest_CIA, p[0], p[1], p[2], p[3]);
+
+ vg_assert(p[0] == 0x44 && p[1] == 0x0 && p[2] == 0x0 && p[3] == 0x2);
+ }
+
#else
# error "ML_(fixup_guest_state_to_restart_syscall): unknown plat"
#endif
VG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid,
Addr ip,
UWord sysnum,
- SysRes sysret,
+ SysRes sres,
Bool restart)
{
/* Note that the sysnum arg seems to contain not-dependable-on info
(Int)tid,
(ULong)ip,
restart ? "True" : "False",
- sysret.isError ? "True" : "False",
- (Long)(Word)sysret.val );
+ sres.isError ? "True" : "False",
+ (Long)(Word)(sres.isError ? sres.err : sres.res) );
vg_assert(VG_(is_valid_tid)(tid));
vg_assert(tid >= 1 && tid < VG_N_THREADS);
Write the SysRes we were supplied with back to the guest
state. */
if (debug)
- VG_(printf)(" completed\n", sysret);
- canonical = convert_SysRes_to_SyscallStatus( sysret );
+ VG_(printf)(" completed\n");
+ canonical = convert_SysRes_to_SyscallStatus( sres );
putSyscallStatusIntoGuestState( &canonical, &th_regs->vex );
sci->status = canonical;
VG_(post_syscall)(tid);