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[] = {
34     CTL_KERN,
35     KERN_PROC,
36     KERN_PROC_PID,
37     getpid()
38   };
39 
40   struct kinfo_proc InfoProc;
41   uptr Len = sizeof(InfoProc);
42   CHECK_EQ(internal_sysctl(Mib, ARRAY_SIZE(Mib), nullptr, (uptr *)&InfoProc, &Len, 0), 0);
43   cb(0, InfoProc.ki_rssize * GetPageSizeCached(), false, stats);
44 }
45 #endif
46 
47 void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
48   const int Mib[] = {
49 #if SANITIZER_FREEBSD
50     CTL_KERN,
51     KERN_PROC,
52     KERN_PROC_VMMAP,
53     getpid()
54 #elif SANITIZER_NETBSD
55     CTL_VM,
56     VM_PROC,
57     VM_PROC_MAP,
58     getpid(),
59     sizeof(struct kinfo_vmentry)
60 #else
61 #error "not supported"
62 #endif
63   };
64 
65   uptr Size = 0;
66   int Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0);
67   CHECK_EQ(Err, 0);
68   CHECK_GT(Size, 0);
69 
70   size_t MmapedSize = Size * 4 / 3;
71   void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
72   Size = MmapedSize;
73   Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0);
74   CHECK_EQ(Err, 0);
75   proc_maps->data = (char *)VmMap;
76   proc_maps->mmaped_size = MmapedSize;
77   proc_maps->len = Size;
78 }
79 
80 bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
81   CHECK(!Error()); // can not fail
82   char *last = data_.proc_self_maps.data + data_.proc_self_maps.len;
83   if (data_.current >= last)
84     return false;
85   const struct kinfo_vmentry *VmEntry =
86       (const struct kinfo_vmentry *)data_.current;
87 
88   segment->start = (uptr)VmEntry->kve_start;
89   segment->end = (uptr)VmEntry->kve_end;
90   segment->offset = (uptr)VmEntry->kve_offset;
91 
92   segment->protection = 0;
93   if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
94     segment->protection |= kProtectionRead;
95   if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
96     segment->protection |= kProtectionWrite;
97   if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
98     segment->protection |= kProtectionExecute;
99 
100   if (segment->filename != NULL && segment->filename_size > 0) {
101     internal_snprintf(segment->filename,
102                       Min(segment->filename_size, (uptr)PATH_MAX), "%s",
103                       VmEntry->kve_path);
104   }
105 
106 #if SANITIZER_FREEBSD
107   data_.current += VmEntry->kve_structsize;
108 #else
109   data_.current += sizeof(*VmEntry);
110 #endif
111 
112   return true;
113 }
114 
115 } // namespace __sanitizer
116 
117 #endif
118