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 29 namespace __sanitizer { 30 31 #if SANITIZER_FREEBSD 32 void 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 46 void 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 61 void 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 94 bool 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 132