1276789Sdim//===-- sanitizer_procmaps_freebsd.cc -------------------------------------===//
2276789Sdim//
3276789Sdim//                     The LLVM Compiler Infrastructure
4276789Sdim//
5276789Sdim// This file is distributed under the University of Illinois Open Source
6276789Sdim// License. See LICENSE.TXT for details.
7276789Sdim//
8276789Sdim//===----------------------------------------------------------------------===//
9276789Sdim//
10276789Sdim// Information about the process mappings (FreeBSD-specific parts).
11276789Sdim//===----------------------------------------------------------------------===//
12276789Sdim
13276789Sdim#include "sanitizer_platform.h"
14276789Sdim#if SANITIZER_FREEBSD
15276789Sdim#include "sanitizer_common.h"
16276789Sdim#include "sanitizer_freebsd.h"
17276789Sdim#include "sanitizer_procmaps.h"
18276789Sdim
19276789Sdim#include <unistd.h>
20276789Sdim#include <sys/sysctl.h>
21276789Sdim#include <sys/user.h>
22276789Sdim
23276789Sdim// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode.
24276789Sdim#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
25276789Sdim# include <osreldate.h>
26276789Sdim# if __FreeBSD_version <= 902001  // v9.2
27276789Sdim#  define kinfo_vmentry xkinfo_vmentry
28276789Sdim# endif
29276789Sdim#endif
30276789Sdim
31276789Sdimnamespace __sanitizer {
32276789Sdim
33276789Sdimvoid ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
34276789Sdim  const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid() };
35276789Sdim  size_t Size = 0;
36276789Sdim  int Err = sysctl(Mib, 4, NULL, &Size, NULL, 0);
37276789Sdim  CHECK_EQ(Err, 0);
38276789Sdim  CHECK_GT(Size, 0);
39276789Sdim
40276789Sdim  size_t MmapedSize = Size * 4 / 3;
41276789Sdim  void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
42276789Sdim  Size = MmapedSize;
43276789Sdim  Err = sysctl(Mib, 4, VmMap, &Size, NULL, 0);
44276789Sdim  CHECK_EQ(Err, 0);
45276789Sdim
46276789Sdim  proc_maps->data = (char*)VmMap;
47276789Sdim  proc_maps->mmaped_size = MmapedSize;
48276789Sdim  proc_maps->len = Size;
49276789Sdim}
50276789Sdim
51276789Sdimbool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
52276789Sdim                               char filename[], uptr filename_size,
53276789Sdim                               uptr *protection) {
54276789Sdim  char *last = proc_self_maps_.data + proc_self_maps_.len;
55276789Sdim  if (current_ >= last) return false;
56276789Sdim  uptr dummy;
57276789Sdim  if (!start) start = &dummy;
58276789Sdim  if (!end) end = &dummy;
59276789Sdim  if (!offset) offset = &dummy;
60276789Sdim  if (!protection) protection = &dummy;
61276789Sdim  struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_;
62276789Sdim
63276789Sdim  *start = (uptr)VmEntry->kve_start;
64276789Sdim  *end = (uptr)VmEntry->kve_end;
65276789Sdim  *offset = (uptr)VmEntry->kve_offset;
66276789Sdim
67276789Sdim  *protection = 0;
68276789Sdim  if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
69276789Sdim    *protection |= kProtectionRead;
70276789Sdim  if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
71276789Sdim    *protection |= kProtectionWrite;
72276789Sdim  if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
73276789Sdim    *protection |= kProtectionExecute;
74276789Sdim
75276789Sdim  if (filename != NULL && filename_size > 0) {
76276789Sdim    internal_snprintf(filename,
77276789Sdim                      Min(filename_size, (uptr)PATH_MAX),
78276789Sdim                      "%s", VmEntry->kve_path);
79276789Sdim  }
80276789Sdim
81276789Sdim  current_ += VmEntry->kve_structsize;
82276789Sdim
83276789Sdim  return true;
84276789Sdim}
85276789Sdim
86276789Sdim}  // namespace __sanitizer
87276789Sdim
88276789Sdim#endif  // SANITIZER_FREEBSD
89