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