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