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
GetMemoryProfile(fill_profile_f cb,uptr * stats)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
ReadProcMaps(ProcSelfMapsBuff * proc_maps)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
Next(MemoryMappedSegment * segment)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