xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_bsd.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
168d75effSDimitry Andric //===-- sanitizer_procmaps_bsd.cpp ----------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // Information about the process mappings
10e8d8bef9SDimitry Andric // (FreeBSD and NetBSD-specific parts).
1168d75effSDimitry Andric //===----------------------------------------------------------------------===//
1268d75effSDimitry Andric 
1368d75effSDimitry Andric #include "sanitizer_platform.h"
14e8d8bef9SDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_NETBSD
1568d75effSDimitry Andric #include "sanitizer_common.h"
1668d75effSDimitry Andric #include "sanitizer_procmaps.h"
1768d75effSDimitry Andric 
1868d75effSDimitry Andric // clang-format off
1968d75effSDimitry Andric #include <sys/types.h>
2068d75effSDimitry Andric #include <sys/sysctl.h>
2168d75effSDimitry Andric // clang-format on
2268d75effSDimitry Andric #include <unistd.h>
2368d75effSDimitry Andric #if SANITIZER_FREEBSD
2468d75effSDimitry Andric #include <sys/user.h>
2568d75effSDimitry Andric #endif
2668d75effSDimitry Andric 
2768d75effSDimitry Andric #include <limits.h>
2868d75effSDimitry Andric 
2968d75effSDimitry Andric namespace __sanitizer {
3068d75effSDimitry Andric 
31bdd1243dSDimitry Andric #if SANITIZER_FREEBSD
GetMemoryProfile(fill_profile_f cb,uptr * stats)32bdd1243dSDimitry Andric void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
33*0fca6ea1SDimitry Andric   const int Mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
34bdd1243dSDimitry Andric 
35*0fca6ea1SDimitry Andric   struct kinfo_proc *InfoProc;
36*0fca6ea1SDimitry Andric   uptr Len = sizeof(*InfoProc);
37*0fca6ea1SDimitry Andric   uptr Size = Len;
38*0fca6ea1SDimitry Andric   InfoProc = (struct kinfo_proc *)MmapOrDie(Size, "GetMemoryProfile()");
39*0fca6ea1SDimitry Andric   CHECK_EQ(
40*0fca6ea1SDimitry Andric       internal_sysctl(Mib, ARRAY_SIZE(Mib), nullptr, (uptr *)InfoProc, &Len, 0),
41*0fca6ea1SDimitry Andric       0);
42*0fca6ea1SDimitry Andric   cb(0, InfoProc->ki_rssize * GetPageSizeCached(), false, stats);
43*0fca6ea1SDimitry Andric   UnmapOrDie(InfoProc, Size, true);
44*0fca6ea1SDimitry Andric }
45*0fca6ea1SDimitry Andric #elif SANITIZER_NETBSD
46*0fca6ea1SDimitry Andric void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
47*0fca6ea1SDimitry Andric   struct kinfo_proc2 *InfoProc;
48*0fca6ea1SDimitry Andric   uptr Len = sizeof(*InfoProc);
49*0fca6ea1SDimitry Andric   uptr Size = Len;
50*0fca6ea1SDimitry Andric   const int Mib[] = {CTL_KERN, KERN_PROC2, KERN_PROC_PID,
51*0fca6ea1SDimitry Andric                      getpid(), (int)Size,  1};
52*0fca6ea1SDimitry Andric   InfoProc = (struct kinfo_proc2 *)MmapOrDie(Size, "GetMemoryProfile()");
53*0fca6ea1SDimitry Andric   CHECK_EQ(
54*0fca6ea1SDimitry Andric       internal_sysctl(Mib, ARRAY_SIZE(Mib), nullptr, (uptr *)InfoProc, &Len, 0),
55*0fca6ea1SDimitry Andric       0);
56*0fca6ea1SDimitry Andric   cb(0, InfoProc->p_vm_rssize * GetPageSizeCached(), false, stats);
57*0fca6ea1SDimitry Andric   UnmapOrDie(InfoProc, Size, true);
58bdd1243dSDimitry Andric }
59bdd1243dSDimitry Andric #endif
60bdd1243dSDimitry Andric 
ReadProcMaps(ProcSelfMapsBuff * proc_maps)6168d75effSDimitry Andric void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
6268d75effSDimitry Andric   const int Mib[] = {
6368d75effSDimitry Andric #if SANITIZER_FREEBSD
6468d75effSDimitry Andric     CTL_KERN,
6568d75effSDimitry Andric     KERN_PROC,
6668d75effSDimitry Andric     KERN_PROC_VMMAP,
6768d75effSDimitry Andric     getpid()
6868d75effSDimitry Andric #elif SANITIZER_NETBSD
6968d75effSDimitry Andric     CTL_VM,
7068d75effSDimitry Andric     VM_PROC,
7168d75effSDimitry Andric     VM_PROC_MAP,
7268d75effSDimitry Andric     getpid(),
7368d75effSDimitry Andric     sizeof(struct kinfo_vmentry)
7468d75effSDimitry Andric #else
7568d75effSDimitry Andric #error "not supported"
7668d75effSDimitry Andric #endif
7768d75effSDimitry Andric   };
7868d75effSDimitry Andric 
7968d75effSDimitry Andric   uptr Size = 0;
8068d75effSDimitry Andric   int Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0);
8168d75effSDimitry Andric   CHECK_EQ(Err, 0);
8268d75effSDimitry Andric   CHECK_GT(Size, 0);
8368d75effSDimitry Andric 
8468d75effSDimitry Andric   size_t MmapedSize = Size * 4 / 3;
8568d75effSDimitry Andric   void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
8668d75effSDimitry Andric   Size = MmapedSize;
8768d75effSDimitry Andric   Err = internal_sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0);
8868d75effSDimitry Andric   CHECK_EQ(Err, 0);
8968d75effSDimitry Andric   proc_maps->data = (char *)VmMap;
9068d75effSDimitry Andric   proc_maps->mmaped_size = MmapedSize;
9168d75effSDimitry Andric   proc_maps->len = Size;
9268d75effSDimitry Andric }
9368d75effSDimitry Andric 
Next(MemoryMappedSegment * segment)9468d75effSDimitry Andric bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
9568d75effSDimitry Andric   CHECK(!Error()); // can not fail
9668d75effSDimitry Andric   char *last = data_.proc_self_maps.data + data_.proc_self_maps.len;
9768d75effSDimitry Andric   if (data_.current >= last)
9868d75effSDimitry Andric     return false;
9968d75effSDimitry Andric   const struct kinfo_vmentry *VmEntry =
10068d75effSDimitry Andric       (const struct kinfo_vmentry *)data_.current;
10168d75effSDimitry Andric 
10268d75effSDimitry Andric   segment->start = (uptr)VmEntry->kve_start;
10368d75effSDimitry Andric   segment->end = (uptr)VmEntry->kve_end;
10468d75effSDimitry Andric   segment->offset = (uptr)VmEntry->kve_offset;
10568d75effSDimitry Andric 
10668d75effSDimitry Andric   segment->protection = 0;
10768d75effSDimitry Andric   if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
10868d75effSDimitry Andric     segment->protection |= kProtectionRead;
10968d75effSDimitry Andric   if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
11068d75effSDimitry Andric     segment->protection |= kProtectionWrite;
11168d75effSDimitry Andric   if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
11268d75effSDimitry Andric     segment->protection |= kProtectionExecute;
11368d75effSDimitry Andric 
11468d75effSDimitry Andric   if (segment->filename != NULL && segment->filename_size > 0) {
11568d75effSDimitry Andric     internal_snprintf(segment->filename,
11668d75effSDimitry Andric                       Min(segment->filename_size, (uptr)PATH_MAX), "%s",
11768d75effSDimitry Andric                       VmEntry->kve_path);
11868d75effSDimitry Andric   }
11968d75effSDimitry Andric 
12068d75effSDimitry Andric #if SANITIZER_FREEBSD
12168d75effSDimitry Andric   data_.current += VmEntry->kve_structsize;
12268d75effSDimitry Andric #else
12368d75effSDimitry Andric   data_.current += sizeof(*VmEntry);
12468d75effSDimitry Andric #endif
12568d75effSDimitry Andric 
12668d75effSDimitry Andric   return true;
12768d75effSDimitry Andric }
12868d75effSDimitry Andric 
12968d75effSDimitry Andric } // namespace __sanitizer
13068d75effSDimitry Andric 
13168d75effSDimitry Andric #endif
132