#include "pub_core_basics.h"
#include "pub_core_vki.h"
#include "pub_core_vkiscnums.h"
+#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy
#include "pub_core_threadstate.h"
#include "pub_core_debuginfo.h" // VG_(di_notify_*)
#include "pub_core_aspacemgr.h"
#include "pub_core_clientstate.h" // VG_(brk_base), VG_(brk_limit)
#include "pub_core_debuglog.h"
#include "pub_core_errormgr.h"
+#include "pub_tool_gdbserver.h" // VG_(gdbserver)
#include "pub_core_libcbase.h"
#include "pub_core_libcassert.h"
#include "pub_core_libcfile.h"
/* that failed. Look elsewhere. */
advised = VG_(am_get_advisory_client_simple)( 0, new_len, &ok );
if (ok) {
+ Bool oldR = old_seg->hasR;
+ Bool oldW = old_seg->hasW;
+ Bool oldX = old_seg->hasX;
/* assert new area does not overlap old */
vg_assert(advised+new_len-1 < old_addr
|| advised > old_addr+old_len-1);
MIN_SIZET(old_len,new_len) );
if (new_len > old_len)
VG_TRACK( new_mem_mmap, advised+old_len, new_len-old_len,
- old_seg->hasR, old_seg->hasW, old_seg->hasX,
- 0/*di_handle*/ );
+ oldR, oldW, oldX, 0/*di_handle*/ );
VG_TRACK(die_mem_munmap, old_addr, old_len);
if (d) {
VG_(discard_translations)( old_addr, old_len, "do_remap(4)" );
#ifdef __NR_shmctl
# ifdef VKI_IPC_64
struct vki_shmid64_ds buf;
- SysRes __res = VG_(do_syscall3)(__NR_shmctl, shmid, VKI_IPC_STAT, (UWord)&buf);
-# else
+# ifdef VGP_amd64_linux
+ /* See bug 222545 comment 7 */
+ SysRes __res = VG_(do_syscall3)(__NR_shmctl, shmid,
+ VKI_IPC_STAT, (UWord)&buf);
+# else
+ SysRes __res = VG_(do_syscall3)(__NR_shmctl, shmid,
+ VKI_IPC_STAT|VKI_IPC_64, (UWord)&buf);
+# endif
+# else /* !def VKI_IPC_64 */
struct vki_shmid_ds buf;
SysRes __res = VG_(do_syscall3)(__NR_shmctl, shmid, VKI_IPC_STAT, (UWord)&buf);
-# endif
+# endif /* def VKI_IPC_64 */
#else
struct vki_shmid_ds buf;
SysRes __res = VG_(do_syscall5)(__NR_ipc, 24 /* IPCOP_shmctl */, shmid,
UWord tmp;
Bool ok;
if (arg1 == 0) {
+ /* arm-linux only: work around the fact that
+ VG_(am_get_advisory_client_simple) produces something that is
+ VKI_PAGE_SIZE aligned, whereas what we want is something
+ VKI_SHMLBA aligned, and VKI_SHMLBA >= VKI_PAGE_SIZE. Hence
+ increase the request size by VKI_SHMLBA - VKI_PAGE_SIZE and
+ then round the result up to the next VKI_SHMLBA boundary.
+ See bug 222545 comment 15. So far, arm-linux is the only
+ platform where this is known to be necessary. */
+ vg_assert(VKI_SHMLBA >= VKI_PAGE_SIZE);
+ if (VKI_SHMLBA > VKI_PAGE_SIZE) {
+ segmentSize += VKI_SHMLBA - VKI_PAGE_SIZE;
+ }
tmp = VG_(am_get_advisory_client_simple)(0, segmentSize, &ok);
- if (ok)
- arg1 = tmp;
+ if (ok) {
+ if (VKI_SHMLBA > VKI_PAGE_SIZE) {
+ arg1 = VG_ROUNDUP(tmp, VKI_SHMLBA);
+ } else {
+ arg1 = tmp;
+ }
+ }
}
else if (!ML_(valid_client_addr)(arg1, segmentSize, tid, "shmat"))
arg1 = 0;
UWord res,
UWord arg0, UWord arg1, UWord arg2 )
{
- UInt segmentSize = get_shm_size ( arg0 );
+ UInt segmentSize = VG_PGROUNDUP(get_shm_size(arg0));
if ( segmentSize > 0 ) {
UInt prot = VKI_PROT_READ|VKI_PROT_WRITE;
Bool d;
cope with the discrepancy, aspacem's sync checker omits the
dev/ino correspondence check in cases where V does not know
the dev/ino. */
- d = VG_(am_notify_client_shmat)( res, VG_PGROUNDUP(segmentSize), prot );
+ d = VG_(am_notify_client_shmat)( res, segmentSize, prot );
/* we don't distinguish whether it's read-only or
* read-write -- it doesn't matter really. */
* call, mmap (aka sys_mmap) which takes the arguments in the
* normal way and the offset in bytes.
*
+ * - On s390x-linux there is mmap (aka old_mmap) which takes the
+ * arguments in a memory block and the offset in bytes. mmap2
+ * is also available (but not exported via unistd.h) with
+ * arguments in a memory block and the offset in pages.
+ *
* To cope with all this we provide a generic handler function here
* and then each platform implements one or more system call handlers
* which call this generic routine after extracting and normalising
return;
}
+ // debug-only printing
+ if (0) {
+ VG_(printf)("ARG1 = %p(%s)\n", (void*)ARG1, (HChar*)ARG1);
+ if (ARG2) {
+ VG_(printf)("ARG2 = ");
+ Int q;
+ HChar** vec = (HChar**)ARG2;
+ for (q = 0; vec[q]; q++)
+ VG_(printf)("%p(%s) ", vec[q], vec[q]);
+ VG_(printf)("\n");
+ } else {
+ VG_(printf)("ARG2 = null\n");
+ }
+ }
+
// Decide whether or not we want to follow along
- trace_this_child = VG_(should_we_trace_this_child)( (HChar*)ARG1 );
+ { // Make 'child_argv' be a pointer to the child's arg vector
+ // (skipping the exe name)
+ HChar** child_argv = (HChar**)ARG2;
+ if (child_argv && child_argv[0] == NULL)
+ child_argv = NULL;
+ trace_this_child = VG_(should_we_trace_this_child)( (HChar*)ARG1, child_argv );
+ }
// Do the important checks: it is a file, is executable, permissions are
// ok, etc. We allow setuid executables to run only in the case when
/* After this point, we can't recover if the execve fails. */
VG_(debugLog)(1, "syswrap", "Exec of %s\n", (Char*)ARG1);
+
+ // Terminate gdbserver if it is active.
+ if (VG_(clo_vgdb) != Vg_VgdbNo) {
+ // If the child will not be traced, we need to terminate gdbserver
+ // to cleanup the gdbserver resources (e.g. the FIFO files).
+ // If child will be traced, we also terminate gdbserver: the new
+ // Valgrind will start a fresh gdbserver after exec.
+ VG_(gdbserver) (0);
+ }
+
/* Resistance is futile. Nuke all other threads. POSIX mandates
this. (Really, nuke them all, since the new process will make
its own new thread.) */