master
  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