xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 //===-- sanitizer_procmaps_bsd.cpp ----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Information about the process mappings
10 // (FreeBSD and NetBSD-specific parts).
11 //===----------------------------------------------------------------------===//
12 
13 #include "sanitizer_platform.h"
14 #if SANITIZER_FREEBSD || SANITIZER_NETBSD
15 #include "sanitizer_common.h"
16 #include "sanitizer_procmaps.h"
17 
18 // clang-format off
19 #include <sys/types.h>
20 #include <sys/sysctl.h>
21 // clang-format on
22 #include <unistd.h>
23 #if SANITIZER_FREEBSD
24 #include <sys/user.h>
25 #endif
26 
27 #include <limits.h>
28 
29 namespace __sanitizer {
30 
31 #if SANITIZER_FREEBSD
32 void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
33   const int Mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
34 
35   struct kinfo_proc *InfoProc;
36   uptr Len = sizeof(*InfoProc);
37   uptr Size = Len;
38   InfoProc = (struct kinfo_proc *)MmapOrDie(Size, "GetMemoryProfile()");
39   CHECK_EQ(
40       internal_sysctl(Mib, ARRAY_SIZE(Mib), nullptr, (uptr *)InfoProc, &Len, 0),
41       0);
42   cb(0, InfoProc->ki_rssize * GetPageSizeCached(), false, stats);
43   UnmapOrDie(InfoProc, Size, true);
44 }
45 #elif SANITIZER_NETBSD
46 void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
47   struct kinfo_proc2 *InfoProc;
48   uptr Len = sizeof(*InfoProc);
49   uptr Size = Len;
50   const int Mib[] = {CTL_KERN, KERN_PROC2, KERN_PROC_PID,
51                      getpid(), (int)Size,  1};
52   InfoProc = (struct kinfo_proc2 *)MmapOrDie(Size, "GetMemoryProfile()");
53   CHECK_EQ(
54       internal_sysctl(Mib, ARRAY_SIZE(Mib), nullptr, (uptr *)InfoProc, &Len, 0),
55       0);
56   cb(0, InfoProc->p_vm_rssize * GetPageSizeCached(), false, stats);
57   UnmapOrDie(InfoProc, Size, true);
58 }
59 #endif
60 
61 void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
62   const int Mib[] = {
63 #if SANITIZER_FREEBSD
64     CTL_KERN,
65     KERN_PROC,
66     KERN_PROC_VMMAP,
67     getpid()
68 #elif SANITIZER_NETBSD
69     CTL_VM,
70     VM_PROC,
71     VM_PROC_MAP,
72     getpid(),
73     sizeof(struct kinfo_vmentry)
74 #else
75 #error "not supported"
76 #endif
77   };
78 
79   uptr Size = 0;
80   int Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0);
81   CHECK_EQ(Err, 0);
82   CHECK_GT(Size, 0);
83 
84   size_t MmapedSize = Size * 4 / 3;
85   void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
86   Size = MmapedSize;
87   Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0);
88   CHECK_EQ(Err, 0);
89   proc_maps->data = (char *)VmMap;
90   proc_maps->mmaped_size = MmapedSize;
91   proc_maps->len = Size;
92 }
93 
94 bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
95   CHECK(!Error()); // can not fail
96   char *last = data_.proc_self_maps.data + data_.proc_self_maps.len;
97   if (data_.current >= last)
98     return false;
99   const struct kinfo_vmentry *VmEntry =
100       (const struct kinfo_vmentry *)data_.current;
101 
102   segment->start = (uptr)VmEntry->kve_start;
103   segment->end = (uptr)VmEntry->kve_end;
104   segment->offset = (uptr)VmEntry->kve_offset;
105 
106   segment->protection = 0;
107   if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
108     segment->protection |= kProtectionRead;
109   if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
110     segment->protection |= kProtectionWrite;
111   if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
112     segment->protection |= kProtectionExecute;
113 
114   if (segment->filename != NULL && segment->filename_size > 0) {
115     internal_snprintf(segment->filename,
116                       Min(segment->filename_size, (uptr)PATH_MAX), "%s",
117                       VmEntry->kve_path);
118   }
119 
120 #if SANITIZER_FREEBSD
121   data_.current += VmEntry->kve_structsize;
122 #else
123   data_.current += sizeof(*VmEntry);
124 #endif
125 
126   return true;
127 }
128 
129 } // namespace __sanitizer
130 
131 #endif
132