Home | History | Annotate | Line # | Download | only in sanitizer_common
      1 //===-- sanitizer_procmaps_bsd.cc -----------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // Information about the process mappings
     11 // (FreeBSD, OpenBSD and NetBSD-specific parts).
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "sanitizer_platform.h"
     15 #if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD
     16 #include "sanitizer_common.h"
     17 #if SANITIZER_FREEBSD
     18 #include "sanitizer_freebsd.h"
     19 #endif
     20 #include "sanitizer_procmaps.h"
     21 
     22 // clang-format off
     23 #include <sys/types.h>
     24 #include <sys/sysctl.h>
     25 // clang-format on
     26 #include <unistd.h>
     27 #if SANITIZER_FREEBSD
     28 #include <sys/user.h>
     29 #endif
     30 
     31 #include <limits.h>
     32 #if SANITIZER_OPENBSD
     33 #define KVME_PROT_READ KVE_PROT_READ
     34 #define KVME_PROT_WRITE KVE_PROT_WRITE
     35 #define KVME_PROT_EXEC KVE_PROT_EXEC
     36 #endif
     37 
     38 // Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode.
     39 #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
     40 #include <osreldate.h>
     41 #if __FreeBSD_version <= 902001 // v9.2
     42 #define kinfo_vmentry xkinfo_vmentry
     43 #endif
     44 #endif
     45 
     46 namespace __sanitizer {
     47 
     48 void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
     49   const int Mib[] = {
     50 #if SANITIZER_FREEBSD
     51     CTL_KERN,
     52     KERN_PROC,
     53     KERN_PROC_VMMAP,
     54     getpid()
     55 #elif SANITIZER_OPENBSD
     56     CTL_KERN,
     57     KERN_PROC_VMMAP,
     58     getpid()
     59 #elif SANITIZER_NETBSD
     60     CTL_VM,
     61     VM_PROC,
     62     VM_PROC_MAP,
     63     getpid(),
     64     sizeof(struct kinfo_vmentry)
     65 #else
     66 #error "not supported"
     67 #endif
     68   };
     69 
     70   uptr Size = 0;
     71   int Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0);
     72   CHECK_EQ(Err, 0);
     73   CHECK_GT(Size, 0);
     74 
     75 #if !SANITIZER_OPENBSD
     76   size_t MmapedSize = Size * 4 / 3;
     77   void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
     78   Size = MmapedSize;
     79   Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0);
     80   CHECK_EQ(Err, 0);
     81   proc_maps->data = (char *)VmMap;
     82 #else
     83   size_t PageSize = GetPageSize();
     84   size_t MmapedSize = Size;
     85   MmapedSize = ((MmapedSize - 1) / PageSize + 1) * PageSize;
     86   char *Mem = (char *)MmapOrDie(MmapedSize, "ReadProcMaps()");
     87   Size = 2 * Size + 10 * sizeof(struct kinfo_vmentry);
     88   if (Size > 0x10000)
     89     Size = 0x10000;
     90   Size = (Size / sizeof(struct kinfo_vmentry)) * sizeof(struct kinfo_vmentry);
     91   Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), Mem, &Size, NULL, 0);
     92   CHECK_EQ(Err, 0);
     93   MmapedSize = Size;
     94   proc_maps->data = Mem;
     95 #endif
     96 
     97   proc_maps->mmaped_size = MmapedSize;
     98   proc_maps->len = Size;
     99 }
    100 
    101 bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
    102   CHECK(!Error()); // can not fail
    103   char *last = data_.proc_self_maps.data + data_.proc_self_maps.len;
    104   if (data_.current >= last)
    105     return false;
    106   const struct kinfo_vmentry *VmEntry =
    107       (const struct kinfo_vmentry *)data_.current;
    108 
    109   segment->start = (uptr)VmEntry->kve_start;
    110   segment->end = (uptr)VmEntry->kve_end;
    111   segment->offset = (uptr)VmEntry->kve_offset;
    112 
    113   segment->protection = 0;
    114   if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
    115     segment->protection |= kProtectionRead;
    116   if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
    117     segment->protection |= kProtectionWrite;
    118   if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
    119     segment->protection |= kProtectionExecute;
    120 
    121 #if !SANITIZER_OPENBSD
    122   if (segment->filename != NULL && segment->filename_size > 0) {
    123     internal_snprintf(segment->filename,
    124                       Min(segment->filename_size, (uptr)PATH_MAX), "%s",
    125                       VmEntry->kve_path);
    126   }
    127 #endif
    128 
    129 #if SANITIZER_FREEBSD
    130   data_.current += VmEntry->kve_structsize;
    131 #else
    132   data_.current += sizeof(*VmEntry);
    133 #endif
    134 
    135   return true;
    136 }
    137 
    138 } // namespace __sanitizer
    139 
    140 #endif
    141