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 | |