| |
| /*--------------------------------------------------------------------*/ |
| /*--- Platform-specific syscalls stuff. arm-linux/syscalls.c ---*/ |
| /*--------------------------------------------------------------------*/ |
| |
| /* |
| This file is part of Valgrind, a dynamic binary instrumentation |
| framework. |
| |
| Copyright (C) 2000-2005 Nicholas Nethercote |
| njn25@cam.ac.uk |
| |
| 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. |
| */ |
| |
| #include "core.h" |
| |
| |
| // See the comment accompanying the declaration of VGA_(thread_syscall)() in |
| // coregrind/core.h for an explanation of what this does, and why. |
| // |
| // XXX: this function and these variables should be assembly code! See the |
| // x86 version. |
| const Addr VGA_(sys_before), VGA_(sys_restarted), |
| VGA_(sys_after), VGA_(sys_done); |
| void VGA_(do_thread_syscall)(UWord sys, |
| UWord arg1, UWord arg2, UWord arg3, |
| UWord arg4, UWord arg5, UWord arg6, |
| UWord *result, /*enum PXState*/Int *statep, |
| /*enum PXState*/Int poststate) |
| { |
| I_die_here; |
| } |
| |
| |
| // Back up to restart a system call. |
| void VGA_(restart_syscall)(ThreadArchState *arch) |
| { |
| I_die_here; |
| #if 0 |
| arch->vex.guest_EIP -= 2; // sizeof(int $0x80) |
| |
| /* Make sure our caller is actually sane, and we're really backing |
| back over a syscall. |
| |
| int $0x80 == CD 80 |
| */ |
| { |
| UChar *p = (UChar *)arch->vex.guest_EIP; |
| |
| if (p[0] != 0xcd || p[1] != 0x80) |
| VG_(message)(Vg_DebugMsg, |
| "?! restarting over syscall at %p %02x %02x\n", |
| arch->vex.guest_EIP, p[0], p[1]); |
| |
| vg_assert(p[0] == 0xcd && p[1] == 0x80); |
| } |
| #endif |
| } |
| |
| /* --------------------------------------------------------------------- |
| PRE/POST wrappers for ARM/Linux-specific syscalls |
| ------------------------------------------------------------------ */ |
| |
| // Nb: See the comment above the generic PRE/POST wrappers in |
| // coregrind/vg_syscalls.c for notes about how they work. |
| |
| #define PRE(name, f) PRE_TEMPLATE(static, arm_linux, name, f) |
| #define POST(name) POST_TEMPLATE(static, arm_linux, name) |
| |
| PRE(sys_syscall, Special) |
| { |
| // Nb!!! |
| // |
| // __NR_syscall is a "higher-order syscall" on ARM; it's all a bit |
| // strange. To implement this, you'll need to shuffle the args down, do |
| // the same for the shadow args, and maybe some other stuff. |
| VG_(printf)("__NR_syscall detected!"); |
| I_die_here; |
| } |
| |
| PRE(sys_clone, Special) |
| { |
| I_die_here; |
| // XXX: maybe this clone stuff could be factored out |
| #if 0 |
| PRINT("sys_clone ( %d, %p, %p, %p, %p )",ARG1,ARG2,ARG3,ARG4,ARG5); |
| // XXX: really not sure about the last two args... if they are really |
| // there, we should do PRE_MEM_READs for both of them... |
| PRE_REG_READ4(int, "clone", |
| unsigned long, flags, void *, child_stack, |
| int *, parent_tidptr, int *, child_tidptr); |
| |
| if (ARG2 == 0 && |
| (ARG1 == (VKI_CLONE_CHILD_CLEARTID|VKI_CLONE_CHILD_SETTID|VKI_SIGCHLD) |
| || ARG1 == (VKI_CLONE_PARENT_SETTID|VKI_SIGCHLD))) |
| { |
| VGA_(gen_sys_fork_before)(tid, tst); |
| SET_RESULT( VG_(do_syscall5)(SYSNO, ARG1, ARG2, ARG3, ARG4, ARG5) ); |
| VGA_(gen_sys_fork_after) (tid, tst); |
| } else { |
| VG_(unimplemented) |
| ("clone(): not supported by Valgrind.\n " |
| "We do support programs linked against\n " |
| "libpthread.so, though. Re-run with -v and ensure that\n " |
| "you are picking up Valgrind's implementation of libpthread.so."); |
| } |
| #endif |
| } |
| |
| PRE(sys_ipc, Special) |
| { |
| // XXX: the situation is complicated by the fact that ARM's ipc |
| // super-syscall, which encompasses shmdt, shmat, getsem, etc, seems to |
| // be the same (or at least similar?) to x86's, and so we want to avoid |
| // duplicating the x86 wrapper here, since it's so big... |
| I_die_here; |
| } |
| |
| POST(sys_ipc) |
| { |
| I_die_here; |
| } |
| |
| #undef PRE |
| #undef POST |
| |
| /* --------------------------------------------------------------------- |
| The ARM/Linux syscall table |
| ------------------------------------------------------------------ */ |
| |
| // Macros for adding ARM/Linux-specific wrappers to the syscall table. Note |
| // that ARM syscall numbers start at __NR_SYSCALL_BASE. |
| #define PLAX_(const, name) \ |
| SYS_WRAPPER_ENTRY_X_(arm_linux, const - __NR_SYSCALL_BASE, name) |
| #define PLAXY(const, name) \ |
| SYS_WRAPPER_ENTRY_XY(arm_linux, const - __NR_SYSCALL_BASE, name) |
| |
| // This table maps from __NR_xxx syscall numbers (from |
| // linux/include/asm-arm/unistd.h) to the appropriate PRE/POST sys_foo() |
| // wrappers on ARM (as per sys_call_table in linux/arch/arm/kernel/entry.S). |
| // |
| // XXX: look at the x86-linux one to see how to do it. |
| |
| const struct SyscallTableEntry VGA_(syscall_table)[] = { |
| // (restart_syscall) // 0 |
| GENX_(__NR_exit, sys_exit), // 1 |
| LINX_(__NR_mount, sys_mount), // 21 |
| PLAX_(__NR_syscall, sys_syscall), // 113 |
| PLAXY(__NR_ipc, sys_ipc), // 117 |
| PLAX_(__NR_clone, sys_clone), // 120 |
| }; |
| |
| const UInt VGA_(syscall_table_size) = |
| sizeof(VGA_(syscall_table)) / sizeof(VGA_(syscall_table)[0]); |
| |
| /*--------------------------------------------------------------------*/ |
| /*--- end ---*/ |
| /*--------------------------------------------------------------------*/ |