]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Bug 495488 - Add FreeBSD getrlimitusage syscall wrapper
authorPaul Floyd <pjfloyd@wanadoo.fr>
Sun, 3 Nov 2024 09:17:17 +0000 (10:17 +0100)
committerPaul Floyd <pjfloyd@wanadoo.fr>
Sun, 3 Nov 2024 09:17:17 +0000 (10:17 +0100)
19 files changed:
.gitignore
NEWS
configure.ac
coregrind/m_debuginfo/debuginfo.c
coregrind/m_main.c
coregrind/m_syswrap/priv_syswrap-freebsd.h
coregrind/m_syswrap/priv_syswrap-generic.h
coregrind/m_syswrap/syswrap-freebsd.c
coregrind/m_syswrap/syswrap-generic.c
coregrind/pub_core_clientstate.h
coregrind/pub_core_debuginfo.h
include/vki/vki-freebsd.h
include/vki/vki-scnums-freebsd.h
memcheck/tests/freebsd/Makefile.am
memcheck/tests/freebsd/getrlimitusage.c [new file with mode: 0644]
memcheck/tests/freebsd/getrlimitusage.stderr.exp [new file with mode: 0644]
memcheck/tests/freebsd/getrlimitusage.vgtest [new file with mode: 0644]
memcheck/tests/freebsd/scalar.c
memcheck/tests/freebsd/scalar.stderr.exp

index e38537a9a63f736713d9087a8c9c84844526211f..cfd943bfc65c11c2aa80a7133959d55e14d024e9 100644 (file)
 /memcheck/tests/freebsd/get_set_login
 /memcheck/tests/freebsd/getfh
 /memcheck/tests/freebsd/getfsstat
+/memcheck/tests/freebsd/getrlimitusage
 /memcheck/tests/freebsd/inlinfo
 /memcheck/tests/freebsd/inlinfo_nested.so
 /memcheck/tests/freebsd/kqueue
diff --git a/NEWS b/NEWS
index 70fa86bc06b42229e76bf020d7b5b5608636f687..97247050907525ce42afb4783de67f18488d3d7c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,7 @@ bugzilla (https://bugs.kde.org/enter_bug.cgi?product=valgrind) rather
 than mailing the developers (or mailing lists) directly -- bugs that
 are not entered into bugzilla tend to get forgotten about or ignored.
 
+495488  Add FreeBSD getrlimitusage syscall wrapper
 
 To see details of a given bug, visit
   https://bugs.kde.org/show_bug.cgi?id=XXXXXX
index 96b19d2aa16efab46d386cbc0e08d30637c3a9b5..ee18cc83a15062cd69bf21c6a0c4fa443eef4709 100755 (executable)
@@ -4955,7 +4955,8 @@ AC_CHECK_FUNCS([     \
         sem_timedwait \
         sem_clockwait_np \
         fdatasync    \
-        getrandom
+        getrandom    \
+        getrlimitusage
         ])
 
 # AC_CHECK_LIB adds any library found to the variable LIBS, and links these
@@ -5009,6 +5010,8 @@ AM_CONDITIONAL([HAVE_FDATASYNC],
                [test x$ac_cv_func_fdatasync = xyes])
 AM_CONDITIONAL([HAVE_GETRANDOM],
                [test x$ac_cv_func_getrandom = xyes])
+AM_CONDITIONAL([HAVE_GETRLIMITUSAGE],
+               [test x$ac_cv_func_getrlimitusage = xyes])
 
 if test x$VGCONF_PLATFORM_PRI_CAPS = xMIPS32_LINUX \
      -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX \
index ad05b9928dcbdfc902fd9eb230de75457cef4af0..11ab47354211c931a12bc9c4afb5b43ba567fedd 100644 (file)
@@ -65,6 +65,9 @@
 # include "priv_readmacho.h"
 # include "priv_readpdb.h"
 #endif
+#if defined(VGO_freebsd)
+#include "pub_core_clientstate.h"
+#endif
 
 
 /* Set this to 1 to enable somewhat minimal debug printing for the
@@ -5145,6 +5148,19 @@ void VG_(load_all_debuginfo) (void)
       VG_(di_load_di)(di);
    }
 }
+
+SizeT VG_(data_size)(void)
+{
+   HChar resolved[1000];
+   VG_(realpath)( VG_(args_the_exename), resolved);
+
+   for (DebugInfo* di = debugInfo_list; di; di = di->next) {
+      if (di->data_size  && VG_(strcmp)(di->soname, "NONE") == 0 && VG_(strcmp)(resolved, di->fsm.filename) == 0) {
+         return VG_PGROUNDUP(di->data_size);
+      }
+   }
+   return 0U;
+}
 #endif
 
 /*--------------------------------------------------------------------*/
index 22b4fea0f36d97b3106dd607ab8f9c15f5cd3b0e..85e744d1575395f9a767a7e80569a621a79bda5d 100644 (file)
@@ -3543,6 +3543,10 @@ void _start_in_C_freebsd ( UWord* pArgc, UWord *initial_sp )
 #  error "Unknown OS"
 #endif
 
+SizeT VG_(get_client_stack_max_size)(void)
+{
+   return the_iifii.clstack_max_size;
+}
 
 Addr VG_(get_initial_client_SP)( void )
 {
index 5b718664001b7bcefbc074c57fec893519210678..8b78c5d742f5bd7ed1b49385d61461a8cfb5bccd 100644 (file)
@@ -538,6 +538,7 @@ DECL_TEMPLATE(freebsd, sys_timerfd_settime) // 587
 
 // __FreeBSD_version 1400507 and 1500012
 DECL_TEMPLATE(freebsd, sys_kcmp) // 588
+DECL_TEMPLATE(freebsd, sys_getrlimitusage) // 589
 
 DECL_TEMPLATE(freebsd, sys_fake_sigreturn)
 
index ec174a152007c0e066a9898e8338f8a2c9583fe1..b888a167ccb492ffa9cd69e677e8f76b64352dba 100644 (file)
@@ -60,6 +60,7 @@ Bool ML_(fd_allowed)(Int fd, const HChar *syscallname, ThreadId tid,
                      Bool isNewFD);
 
 extern void ML_(record_fd_close)               (ThreadId tid, Int fd);
+extern Int  ML_(get_fd_count)                  (void);
 extern void ML_(record_fd_close_range)         (ThreadId tid, Int fd);
 extern void ML_(record_fd_open_named)          (ThreadId tid, Int fd);
 extern void ML_(record_fd_open_nameless)       (ThreadId tid, Int fd);
index 85b60c8f35b58ac32f1d2eb9ec37c3dd11997515..f5516420fb38d1274aacd72a0c21444d5482e2c3 100644 (file)
@@ -6915,6 +6915,54 @@ PRE(sys_kcmp)
    }
 }
 
+// SYS_getrlimitusage 589
+// from syscalls.master
+// int getrlimitusage(u_int which, int flags, _Out_ rlim_t *res);
+PRE(sys_getrlimitusage)
+{
+   PRINT("sys_getrlimitusage(%lu, %ld, %#" FMT_REGWORD "x )", ARG1, SARG2, ARG3);
+   PRE_REG_READ3(int, "getrlimitusage", u_int, which, int, flags, vki_rlim_t*, res);
+
+   PRE_MEM_WRITE("getrlimitusage(res)", ARG3, sizeof(vki_rlim_t));
+}
+
+POST(sys_getrlimitusage)
+{
+   POST_MEM_WRITE(ARG3, sizeof(vki_rlim_t));
+
+   // flags can be GETRLIMITUSAGE_EUID or not
+   // not sure what that means?
+
+   // we need to set the values for NOFILE DATA and STACK
+   vki_rlim_t* res = (vki_rlim_t*)ARG3;
+   switch (ARG1) {
+   case VKI_RLIMIT_NOFILE:
+      *res = ML_(get_fd_count)() + 3;
+      break;
+   case VKI_RLIMIT_DATA:
+      /*
+       * The OS initializes this the the size of the .data for the exe.
+       * We read this in readelf.c.
+       */
+      *res = VG_(data_size)() + VG_(brk_limit) - VG_(brk_base);
+      break;
+   case VKI_RLIMIT_STACK:
+      /*
+       * The main client stack is quite different when running under Valgrind. 
+       * See aspacemg-linux.c for details, but in short on 64bit systems
+       * the main stack starts with 128k reserved and a 512M limit.
+       * Valgrind just has one value, 16M by default (can be changed with
+       * --main-stacksize). Maybe we should use something more like the OS
+       * but it doesn't seem that important.
+       */
+      *res = VG_(get_client_stack_max_size)();
+      break;
+   default:
+      // do nothing
+      break;
+   }
+}
+
 #undef PRE
 #undef POST
 
@@ -7606,6 +7654,7 @@ const SyscallTableEntry ML_(syscall_table)[] = {
    BSDXY(__NR_timerfd_settime,  sys_timerfd_settime),   // 586
    BSDXY(__NR_timerfd_gettime,  sys_timerfd_gettime),   // 587
    BSDX_(__NR_kcmp,             sys_kcmp),              // 588
+   BSDXY(__NR_getrlimitusage,   sys_getrlimitusage),    // 589
 
    BSDX_(__NR_fake_sigreturn,   sys_fake_sigreturn),    // 1000, fake sigreturn
 
index 1d80d09288ed0f429d2499fc2b5829550897a579..d6b10780dc2af867cd23651fb20d1c4abaf9c9f1 100644 (file)
@@ -553,6 +553,12 @@ static OpenFd *allocated_fds = NULL;
 /* Count of open file descriptors. */
 static Int fd_count = 0;
 
+
+Int ML_(get_fd_count)(void)
+{
+   return fd_count;
+}
+
 /* Close_range caller might want to close very wide range of file descriptors,
    up to 0U.  We want to avoid iterating through such a range in a normall
    close_range, just up to any open file descriptor.  Also, unlike
index dceece9b90ba83dc51e0258c205f2af770979791..06d0fe343bf574477e4d662be72237bf40e16e8b 100644 (file)
@@ -98,6 +98,9 @@ extern Addr VG_(client_freeres_wrapper);
    VG_(get_StackTrace) in m_stacktrace.c for further info. */
 extern Addr VG_(client__dl_sysinfo_int80);
 
+/* Get the maximum client stacksize. */
+extern SizeT VG_(get_client_stack_max_size)(void);
+
 /* Obtains the initial client stack pointer from the finalised image info. */
 extern Addr VG_(get_initial_client_SP)(void);
 
index 4d6ebda816da7c9851cffa7a0d50c8c532b002da..64fcd3428a8d1b8425186b504d8c36a4aeed425e 100644 (file)
@@ -158,6 +158,8 @@ extern UInt VG_(debuginfo_generation) (void);
     we can't open executable files to get the debuginfo after
     entering capability mode. */
 extern void VG_(load_all_debuginfo) (void);
+/* Get the size of .data for the client exe */
+extern SizeT VG_(data_size)(void);
 #endif
 
 
index 7b35428a3c8ff1566eb6c10817f834dd8c5afe7a..a49650b2bc679d54b67094d5e21f7e21b5bc9d0e 100644 (file)
@@ -1230,6 +1230,8 @@ struct vki_rlimit {
 #define VKI_RLIMIT_CORE    4  /* max core file size */
 #define VKI_RLIMIT_NOFILE  8  /* max number of open files */
 
+#define VKI_GETRLIMITUSAGE_EUID 0x0001
+
 struct vki___wrusage {
    struct vki_rusage   wru_self;
    struct vki_rusage   wru_children;
index 852f9833ab32928aa21c38525dc64ec2add9d2a3..098b722f485c98ade7a31aeb51a169753156c647 100644 (file)
 // __FreeBSD_version 1400507 and 1500012
 #define __NR_kcmp                588
 
+#define __NR_getrlimitusage      589
+
 #define __NR_fake_sigreturn      1000
 
 #endif /* VKI_UNISTD_FREEBSD_H */
index b2e84fc03e272f3003ba5f20a250a001f908b26c..4b6b36c6ce00b0ea989eaa617bbac9a556b38746 100644 (file)
@@ -67,6 +67,7 @@ EXTRA_DIST = \
        getfsstat.stderr.exp \
        getfsstat.supp \
                getfsstat.stderr.exp-x86 \
+       getrlimitusage.vgtest getrlimitusage.stderr.exp \
        kqueue.vgtest \
        kqueue.stderr.exp \
        kqueue.stdout.exp \
@@ -172,6 +173,10 @@ if HAVE_AIO_READV
 check_PROGRAMS += aiov
 endif
 
+if HAVE_GETRLIMITUSAGE
+check_PROGRAMS += getrlimitusage
+endif
+
 inlinfo_SOURCES = inlinfo.c
 inlinfo_DEPENDENCIES = inlinfo_nested.so
 inlinfo_LDFLAGS = -Wl,-rpath,$(top_builddir)/memcheck/tests/freebsd
diff --git a/memcheck/tests/freebsd/getrlimitusage.c b/memcheck/tests/freebsd/getrlimitusage.c
new file mode 100644 (file)
index 0000000..123ab18
--- /dev/null
@@ -0,0 +1,106 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#define _RLIMIT_IDENT
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <unistd.h>
+
+static void usage(void)
+{
+    fprintf(stderr, "usage: getrlimitusage [-e] [-p pid]\n");
+    exit(2);
+}
+
+int main(int argc, char *argv[])
+{
+    rlim_t res;
+    int c, flags;
+
+    flags = 0;
+    while ((c = getopt(argc, argv, "e")) != -1)
+    {
+        switch (c)
+        {
+        case 'e':
+            flags |= GETRLIMITUSAGE_EUID;
+            break;
+        case '?':
+        default:
+            usage();
+        }
+    }
+    argc -= optind;
+    argv += optind;
+    if (argc != 0)
+        usage();
+
+    for (unsigned i = 0;; i++)
+    {
+        if (getrlimitusage(i, flags, &res) == -1)
+        {
+            if (errno == ENXIO)
+            {
+                res = -1;
+            }
+            else
+            {
+                if (errno != EINVAL)
+                    err(1, "getrlimitusage(%d)", errno);
+                break;
+            }
+        }
+        // add some rounding to try to make regtest stable
+        switch (i)
+        {
+        case 7:
+        case 9:
+        case 12:
+        case 15:
+            res = 0U;
+            break;
+        case 5:
+            res = res/100000 * 100000;
+            break;
+        case 10:
+            res = res/1000 * 1000;
+            break;
+        default:
+             break;
+        }
+        fprintf(stderr, "%s (%d):\t%jd\n", i < nitems(rlimit_ident) ? rlimit_ident[i] : "unknown", i, (uintmax_t)res
+);
+    }
+    exit(0);
+}
diff --git a/memcheck/tests/freebsd/getrlimitusage.stderr.exp b/memcheck/tests/freebsd/getrlimitusage.stderr.exp
new file mode 100644 (file)
index 0000000..2a1ecb3
--- /dev/null
@@ -0,0 +1,16 @@
+cpu (0):       0
+fsize (1):     -1
+data (2):      4096
+stack (3):     16777216
+core (4):      -1
+rss (5):       41800000
+memlock (6):   0
+nproc (7):     0
+nofile (8):    3
+sbsize (9):    0
+vmem (10):     106414000
+npts (11):     0
+swap (12):     0
+kqueues (13):  0
+umtx (14):     0
+pipebuf (15):  0
diff --git a/memcheck/tests/freebsd/getrlimitusage.vgtest b/memcheck/tests/freebsd/getrlimitusage.vgtest
new file mode 100644 (file)
index 0000000..dbcd333
--- /dev/null
@@ -0,0 +1,3 @@
+prereq: test -e ./getrlimitusage
+prog: getrlimitusage
+vgopts: -q
index 5aecfebacfcb6b22fe31bbcfa9edd2dcdabfd6c0..7ad3099a04cca2cbd0f1b601d7aaf3fa40313567 100644 (file)
@@ -2408,6 +2408,50 @@ int main(void)
    FAKE_SY("\n");
 #endif
 
+   /* SYS_kcmp                           588 */
+#if defined(SYS_kcmp)
+   GO(SYS_kcmp, "5s 0m");
+   SY(SYS_kcmp, x0+1, x0+2, x0+3, x0+4, x0+5);
+#else
+   FAKE_GO("588:                SYS_kcmp 5s 0m");
+   FAKE_SY("Syscall param kcmp(pid1) contains uninitialised byte(s)\n");
+   FAKE_SY("   ...\n");
+   FAKE_SY("\n");
+   FAKE_SY("Syscall param kcmp(pid2) contains uninitialised byte(s)\n");
+   FAKE_SY("   ...\n");
+   FAKE_SY("\n");
+   FAKE_SY("Syscall param kcmp(type) contains uninitialised byte(s)\n");
+   FAKE_SY("   ...\n");
+   FAKE_SY("\n");
+   FAKE_SY("Syscall param kcmp(idx1) contains uninitialised byte(s)\n");
+   FAKE_SY("   ...\n");
+   FAKE_SY("\n");
+   FAKE_SY("Syscall param kcmp(idx2) contains uninitialised byte(s)\n");
+   FAKE_SY("    ...\n");
+   FAKE_SY("\n");
+#endif
+
+   /* SYS_getrlimitusage                 589 */
+#if defined(SYS_getrlimitusage)
+   GO(SYS_getrlimitusage, "3s, 1m");
+   SY(SYS_getrlimitusage, x0+3, x0, x0+2);
+#else
+   FAKE_GO("589:      SYS_getrlimitusage 3s, 1m");
+   FAKE_SY("Syscall param getrlimitusage(which) contains uninitialised byte(s)\n");
+   FAKE_SY("   ...\n");
+   FAKE_SY("\n");
+   FAKE_SY("Syscall param getrlimitusage(flags) contains uninitialised byte(s)\n");
+   FAKE_SY("   ...\n");
+   FAKE_SY("\n");
+   FAKE_SY("Syscall param getrlimitusage(res) contains uninitialised byte(s)\n");
+   FAKE_SY("   ...\n");
+   FAKE_SY("\n");
+   FAKE_SY("Syscall param getrlimitusage(res) points to unaddressable byte(s)\n");
+   FAKE_SY("   ...\n");
+   FAKE_SY("  Address 0x........ is not stack'd, malloc'd or (recently) free'd\n");
+   FAKE_SY("\n");
+#endif 
+
    /* SYS_exit                    1 */
    GO(SYS_exit, "1s 0m");
    SY(SYS_exit, x0); FAIL;
index ed5f0a9b15f8ac4f99da39374a6de0981b6bf0c4..4a57e002aa70187d67d6bf8c76dd6fa6bcdb125b 100644 (file)
@@ -5710,6 +5710,40 @@ Syscall param timerfd_settime(old_value) points to unaddressable byte(s)
    ...
  Address 0x........ is not stack'd, malloc'd or (recently) free'd
 
+---------------------------------------------------------
+588:                SYS_kcmp 5s 0m
+---------------------------------------------------------
+Syscall param kcmp(pid1) contains uninitialised byte(s)
+   ...
+
+Syscall param kcmp(pid2) contains uninitialised byte(s)
+   ...
+
+Syscall param kcmp(type) contains uninitialised byte(s)
+   ...
+
+Syscall param kcmp(idx1) contains uninitialised byte(s)
+   ...
+
+Syscall param kcmp(idx2) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+589:      SYS_getrlimitusage 3s, 1m
+---------------------------------------------------------
+Syscall param getrlimitusage(which) contains uninitialised byte(s)
+   ...
+
+Syscall param getrlimitusage(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param getrlimitusage(res) contains uninitialised byte(s)
+   ...
+
+Syscall param getrlimitusage(res) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
 ---------------------------------------------------------
   1:                SYS_exit 1s 0m
 ---------------------------------------------------------