Blob Blame History Raw
diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
index 2336c29..0f8e07a 100644
--- a/coregrind/m_syswrap/syswrap-linux.c
+++ b/coregrind/m_syswrap/syswrap-linux.c
@@ -5277,8 +5277,25 @@ PRE(sys_utimensat)
                  int, dfd, char *, filename, struct timespec *, utimes, int, flags);
    if (ARG2 != 0)
       PRE_MEM_RASCIIZ( "utimensat(filename)", ARG2 );
-   if (ARG3 != 0)
-      PRE_MEM_READ( "utimensat(tvp)", ARG3, 2 * sizeof(struct vki_timespec) );
+   if (ARG3 != 0) {
+      /* If timespec.tv_nsec has the special value UTIME_NOW or UTIME_OMIT
+         then the tv_sec field is ignored.  */
+      struct vki_timespec *times = (struct vki_timespec *)(Addr)ARG3;
+      PRE_MEM_READ( "utimensat(times[0].tv_nsec)",
+                    (Addr)&times[0].tv_nsec, sizeof(times[0].tv_nsec));
+      PRE_MEM_READ( "utimensat(times[1].tv_nsec)",
+                    (Addr)&times[1].tv_nsec, sizeof(times[1].tv_nsec));
+      if (ML_(safe_to_deref)(times, 2 * sizeof(struct vki_timespec))) {
+         if (times[0].tv_nsec != VKI_UTIME_NOW
+             && times[0].tv_nsec != VKI_UTIME_OMIT)
+            PRE_MEM_READ( "utimensat(times[0].tv_sec)",
+                          (Addr)&times[0].tv_sec, sizeof(times[0].tv_sec));
+         if (times[1].tv_nsec != VKI_UTIME_NOW
+             && times[1].tv_nsec != VKI_UTIME_OMIT)
+            PRE_MEM_READ( "utimensat(times[1].tv_sec)",
+                          (Addr)&times[1].tv_sec, sizeof(times[1].tv_sec));
+      }
+   }
 }
 
 PRE(sys_newfstatat)
diff --git a/include/vki/vki-linux.h b/include/vki/vki-linux.h
index 7072080..bf0c1aa 100644
--- a/include/vki/vki-linux.h
+++ b/include/vki/vki-linux.h
@@ -283,6 +283,10 @@ struct vki_timespec {
 	long		tv_nsec;	/* nanoseconds */
 };
 
+/* Special values for vki_timespec.tv_nsec when used with utimensat.  */
+#define VKI_UTIME_NOW  ((1l << 30) - 1l)
+#define VKI_UTIME_OMIT ((1l << 30) - 2l)
+
 struct vki_timeval {
 	vki_time_t	tv_sec;		/* seconds */
 	vki_suseconds_t	tv_usec;	/* microseconds */