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#if SANITIZER_FREEBSD
17#include "sanitizer_freebsd.h"
18#endif
19#include "sanitizer_procmaps.h"
20
21// clang-format off
22#include <sys/types.h>
23#include <sys/sysctl.h>
24// clang-format on
25#include <unistd.h>
26#if SANITIZER_FREEBSD
27#include <sys/user.h>
28#endif
29
30#include <limits.h>
31
32// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode.
33#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
34#include <osreldate.h>
35#if __FreeBSD_version <= 902001 // v9.2
36#define kinfo_vmentry xkinfo_vmentry
37#endif
38#endif
39
40namespace __sanitizer {
41
42void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
43  const int Mib[] = {
44#if SANITIZER_FREEBSD
45    CTL_KERN,
46    KERN_PROC,
47    KERN_PROC_VMMAP,
48    getpid()
49#elif SANITIZER_NETBSD
50    CTL_VM,
51    VM_PROC,
52    VM_PROC_MAP,
53    getpid(),
54    sizeof(struct kinfo_vmentry)
55#else
56#error "not supported"
57#endif
58  };
59
60  uptr Size = 0;
61  int Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0);
62  CHECK_EQ(Err, 0);
63  CHECK_GT(Size, 0);
64
65  size_t MmapedSize = Size * 4 / 3;
66  void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
67  Size = MmapedSize;
68  Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0);
69  CHECK_EQ(Err, 0);
70  proc_maps->data = (char *)VmMap;
71  proc_maps->mmaped_size = MmapedSize;
72  proc_maps->len = Size;
73}
74
75bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
76  CHECK(!Error()); // can not fail
77  char *last = data_.proc_self_maps.data + data_.proc_self_maps.len;
78  if (data_.current >= last)
79    return false;
80  const struct kinfo_vmentry *VmEntry =
81      (const struct kinfo_vmentry *)data_.current;
82
83  segment->start = (uptr)VmEntry->kve_start;
84  segment->end = (uptr)VmEntry->kve_end;
85  segment->offset = (uptr)VmEntry->kve_offset;
86
87  segment->protection = 0;
88  if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
89    segment->protection |= kProtectionRead;
90  if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
91    segment->protection |= kProtectionWrite;
92  if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
93    segment->protection |= kProtectionExecute;
94
95  if (segment->filename != NULL && segment->filename_size > 0) {
96    internal_snprintf(segment->filename,
97                      Min(segment->filename_size, (uptr)PATH_MAX), "%s",
98                      VmEntry->kve_path);
99  }
100
101#if SANITIZER_FREEBSD
102  data_.current += VmEntry->kve_structsize;
103#else
104  data_.current += sizeof(*VmEntry);
105#endif
106
107  return true;
108}
109
110} // namespace __sanitizer
111
112#endif
113