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
29namespace __sanitizer {
30
31#if SANITIZER_FREEBSD
32void 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
46void 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
61void 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
94bool 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