]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
FreeBSD: experimental fix for --sanity-level=3 and above
authorPaul Floyd <pjfloyd@wanadoo.fr>
Sun, 25 Feb 2024 18:10:37 +0000 (19:10 +0100)
committerPaul Floyd <pjfloyd@wanadoo.fr>
Sun, 25 Feb 2024 18:10:37 +0000 (19:10 +0100)
Previously this failed due to split mmap mappings for MAP_STACK.
This change tries to piece together such stack mappings. This
mainly affects multithreaded apps when they create their thread
stacks.

coregrind/m_aspacemgr/aspacemgr-linux.c
coregrind/m_aspacemgr/priv_aspacemgr.h
coregrind/m_main.c
include/vki/vki-freebsd.h

index aab9eb8d18a9cf769bfb2a23f352b7a8a4cf85e5..4ed8e40ff9e5acd3dc0a122828feb76c329169e0 100644 (file)
@@ -3906,6 +3906,68 @@ Bool VG_(get_changed_segments)(
 /*------BEGIN-procmaps-parser-for-Freebsd------------------------*/
 #elif defined(VGO_freebsd)
 
+/*
+ * Some more nasty hacks.
+ *
+ * On FreeBSD mmap with MAP_STACK will result in TWO adjacent areas being mapped.
+ * Assuming a grow down stack, the one in the lower address is a growth guard
+ * area. The one in the higher area is the stack. The kernel will automatically
+ * extend the stack into the growth guard. Valgrind doesn't see any of that.
+ * When we see mapped memory like that, we need to try to merge them so that
+ * they match the mmap that Valgrind saw and recorded.
+ *
+ * There is also the initial stack. Valgrind will have already recorded that
+ * with parse_procselfmaps. So we don't want to merge that.
+ */
+static char* maybe_merge_procmap_stack(char* p,  struct vki_kinfo_vmentry *kve, Addr* pEndPlusOne, UInt* pProt)
+{
+   static Bool sgrowsiz_read = False;
+   static SizeT kern_sgrowsiz;
+   if (!sgrowsiz_read) {
+      SizeT sysctl_size = sizeof(SizeT);
+      VG_(sysctlbyname)("kern.sgrowsiz", &kern_sgrowsiz, &sysctl_size, NULL, 0);
+      sgrowsiz_read = True;
+   }
+   char* p_next = p + kve->kve_structsize;
+   struct vki_kinfo_vmentry *kve_next = (struct vki_kinfo_vmentry *)(p_next);
+
+#if defined(VGP_amd64_freebsd)
+   // I think that this is the stacksize rlimit
+   // I could use sysctl kern.maxssiz for this
+   if ( *pEndPlusOne + kern_sgrowsiz - kve->kve_start == 512ULL*1024ULL*1024ULL) {
+      return p;
+   }
+#elif defined(VGP_x86_freebsd)
+   // sysctl kern.maxssiz OK for x86 on x86 but not x86 on amd64
+   if ( *pEndPlusOne + kern_sgrowsiz - kve->kve_start == 64ULL*1024ULL*1024ULL) {
+      return p;
+   }
+#endif
+
+   while (kve_next->kve_protection & VKI_KVME_PROT_READ &&
+          kve_next->kve_protection & VKI_KVME_PROT_WRITE &&
+          kve_next->kve_flags & VKI_KVME_FLAG_GROWS_DOWN &&
+          kve_next->kve_end - kve_next->kve_start == kern_sgrowsiz) {
+
+
+      *pEndPlusOne += kern_sgrowsiz;
+      if (kve_next->kve_protection & VKI_KVME_PROT_READ) {
+         *pProt |= VKI_PROT_READ;
+      }
+      if (kve_next->kve_protection & VKI_KVME_PROT_WRITE) {
+         *pProt |= VKI_PROT_WRITE;
+      }
+      if (kve_next->kve_protection & VKI_KVME_PROT_EXEC) {
+         *pProt |= VKI_PROT_EXEC;
+      }
+      p_next += kve->kve_structsize;
+      kve_next = (struct vki_kinfo_vmentry *)(p_next);
+   }
+   p_next -= kve->kve_structsize;
+   return p_next;
+}
+
+
 /*
  * PJF 2023-09-23
  *
@@ -3928,7 +3990,7 @@ Bool VG_(get_changed_segments)(
  * the RW PT_LOAD.
  *
  * For instance, objdump -p for memcheck-amd64-freebsd contains
- *     LOAD off    0x0000000000000000 vaddr 0x0000000038000000 paddr 0x0000000038000000 align 2**12
+ *    LOAD off    0x0000000000000000 vaddr 0x0000000038000000 paddr 0x0000000038000000 align 2**12
  *         filesz 0x00000000000c5124 memsz 0x00000000000c5124 flags r--
  *    LOAD off    0x00000000000c5130 vaddr 0x00000000380c6130 paddr 0x00000000380c6130 align 2**12
  *         filesz 0x00000000001b10df memsz 0x00000000001b10df flags r-x
@@ -4048,6 +4110,12 @@ static void parse_procselfmaps (
       if (record_gap && gapStart < start)
          (*record_gap) ( gapStart, start-gapStart );
 
+      if (kve->kve_type == VKI_KVME_TYPE_GUARD &&
+          record_mapping == sync_check_mapping_callback &&
+          VG_(clo_sanity_level) >= 3)  {
+         p = maybe_merge_procmap_stack(p, kve, &endPlusOne, &prot);
+      }
+
       if (record_mapping && start < endPlusOne) {
          (*record_mapping) ( start, endPlusOne-start,
                              prot, dev, ino,
@@ -4064,6 +4132,11 @@ static void parse_procselfmaps (
       }
 
       gapStart = endPlusOne;
+      // PJF I think that we need to walk this based on each entry's kve_structsize
+      // because sysctl kern.coredump_pack_fileinfo (on by default) can cause this
+      // array to be packed (for core dumps)
+      // the packing consists of only storing the used part of kve_path rather than
+      // the full 1024 bytes
       p += kve->kve_structsize;
    }
  
index 161c5c295441b40b2a0825b7d35f9afb7d61d01e..0c8a807f22d3108211bcfe335ff31bb75c45a0cc 100644 (file)
 
 #include "pub_core_options.h"    // VG_(clo_sanity_level)
 
+#if defined(VGO_freebsd)
+#include "pub_core_libcproc.h"   // VG_(sysctlbyname)
+#endif
+
 #include "pub_core_aspacemgr.h"  // self
 
 
index 042b2787c7d422a7997d02105ee028f28574f473..10b2d9be97d035ea5f67ff9bd970caffe7bad806 100644 (file)
@@ -1110,6 +1110,13 @@ void main_process_cmd_line_options( void )
          here. */
    }
 
+#if defined(VGO_freebsd)
+   if (VG_(clo_sanity_level) >= 3) {
+      VG_(debugLog)(0, "main", "Warning: due to transparent memory mappings with MAP_STACK\n");
+      VG_(debugLog)(0, "main", "--sanity-level=3 and above may give spurious errors.\n");
+   }
+#endif
+
    /* All non-logging-related options have been checked.  If the logging
       option specified is ok, we can switch to it, as we know we won't
       have to generate any other command-line-related error messages.
index bd4f099765bc8ddec1d46ccff7bf205f6a017774..1267eb3b3c15b8c7bb284b5ff1a8c5ab63fd15c7 100644 (file)
@@ -2164,6 +2164,8 @@ typedef struct vki_cap_rights       vki_cap_rights_t;
 #define VKI_KVME_TYPE_DEVICE        4
 #define VKI_KVME_TYPE_PHYS          5
 #define VKI_KVME_TYPE_DEAD          6
+#define VKI_KVME_TYPE_MGTDEVICE     8
+#define VKI_KVME_TYPE_GUARD         9
 #define VKI_KVME_TYPE_UNKNOWN       255
 
 #define VKI_KVME_PROT_READ          0x00000001
@@ -2172,6 +2174,11 @@ typedef struct vki_cap_rights       vki_cap_rights_t;
 
 #define VKI_KVME_FLAG_COW           0x00000001
 #define VKI_KVME_FLAG_NEEDS_COPY    0x00000002
+#define VKI_KVME_FLAG_NOCOREDUMP    0x00000004
+#define VKI_KVME_FLAG_SUPER         0x00000008
+#define VKI_KVME_FLAG_GROWS_UP      0x00000010
+#define VKI_KVME_FLAG_GROWS_DOWN    0x00000020
+#define VKI_KVME_FLAG_USER_WIRED    0x00000040
 
 struct vki_kinfo_vmentry {
    int   kve_structsize;
@@ -2559,8 +2566,9 @@ struct vki_ps_strings {
 
 
 #define VKI_NT_FREEBSD_ABI_TAG 1
-#define VKI_NT_FREEBSD_FEATURE_CTL     4
-#define VKI_NT_FREEBSD_FCTL_WXNEEDED   0x00000008
+#define VKI_NT_FREEBSD_FEATURE_CTL 4
+#define VKI_NT_FREEBSD_FCTL_STKGAP_DISABLE 0x00000004
+#define VKI_NT_FREEBSD_FCTL_WXNEEDED 0x00000008
 
 // See syswrap-freebsd.c PRE/POST(sys_ioctl)
 #if 0