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 40 namespace __sanitizer { 41 42 #if SANITIZER_FREEBSD 43 void GetMemoryProfile(fill_profile_f cb, uptr *stats) { 44 const int Mib[] = { 45 CTL_KERN, 46 KERN_PROC, 47 KERN_PROC_PID, 48 getpid() 49 }; 50 51 struct kinfo_proc InfoProc; 52 uptr Len = sizeof(InfoProc); 53 CHECK_EQ(internal_sysctl(Mib, ARRAY_SIZE(Mib), nullptr, (uptr *)&InfoProc, &Len, 0), 0); 54 cb(0, InfoProc.ki_rssize * GetPageSizeCached(), false, stats); 55 } 56 #endif 57 58 void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { 59 const int Mib[] = { 60 #if SANITIZER_FREEBSD 61 CTL_KERN, 62 KERN_PROC, 63 KERN_PROC_VMMAP, 64 getpid() 65 #elif SANITIZER_NETBSD 66 CTL_VM, 67 VM_PROC, 68 VM_PROC_MAP, 69 getpid(), 70 sizeof(struct kinfo_vmentry) 71 #else 72 #error "not supported" 73 #endif 74 }; 75 76 uptr Size = 0; 77 int Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0); 78 CHECK_EQ(Err, 0); 79 CHECK_GT(Size, 0); 80 81 size_t MmapedSize = Size * 4 / 3; 82 void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()"); 83 Size = MmapedSize; 84 Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0); 85 CHECK_EQ(Err, 0); 86 proc_maps->data = (char *)VmMap; 87 proc_maps->mmaped_size = MmapedSize; 88 proc_maps->len = Size; 89 } 90 91 bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { 92 CHECK(!Error()); // can not fail 93 char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; 94 if (data_.current >= last) 95 return false; 96 const struct kinfo_vmentry *VmEntry = 97 (const struct kinfo_vmentry *)data_.current; 98 99 segment->start = (uptr)VmEntry->kve_start; 100 segment->end = (uptr)VmEntry->kve_end; 101 segment->offset = (uptr)VmEntry->kve_offset; 102 103 segment->protection = 0; 104 if ((VmEntry->kve_protection & KVME_PROT_READ) != 0) 105 segment->protection |= kProtectionRead; 106 if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0) 107 segment->protection |= kProtectionWrite; 108 if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0) 109 segment->protection |= kProtectionExecute; 110 111 if (segment->filename != NULL && segment->filename_size > 0) { 112 internal_snprintf(segment->filename, 113 Min(segment->filename_size, (uptr)PATH_MAX), "%s", 114 VmEntry->kve_path); 115 } 116 117 #if SANITIZER_FREEBSD 118 data_.current += VmEntry->kve_structsize; 119 #else 120 data_.current += sizeof(*VmEntry); 121 #endif 122 123 return true; 124 } 125 126 } // namespace __sanitizer 127 128 #endif 129