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[] = {
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
47void 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
80bool 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