xref: /freebsd/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_solaris.cpp (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 //===-- sanitizer_procmaps_solaris.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 (Solaris-specific parts).
10 //===----------------------------------------------------------------------===//
11 
12 // Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
13 #undef _FILE_OFFSET_BITS
14 
15 // Avoid conflict between `_TIME_BITS` defined vs. `_FILE_OFFSET_BITS`
16 // undefined in some Linux configurations.
17 #undef _TIME_BITS
18 #include "sanitizer_platform.h"
19 #if SANITIZER_SOLARIS
20 #  include <fcntl.h>
21 #  include <limits.h>
22 #  include <procfs.h>
23 
24 #  include "sanitizer_common.h"
25 #  include "sanitizer_procmaps.h"
26 
27 namespace __sanitizer {
28 
29 void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
30   uptr fd = internal_open("/proc/self/xmap", O_RDONLY);
31   CHECK_NE(fd, -1);
32   uptr Size = internal_filesize(fd);
33   CHECK_GT(Size, 0);
34 
35   // Allow for additional entries by following mmap.
36   size_t MmapedSize = Size * 4 / 3;
37   void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
38   Size = internal_read(fd, VmMap, MmapedSize);
39   CHECK_NE(Size, -1);
40   internal_close(fd);
41   proc_maps->data = (char *)VmMap;
42   proc_maps->mmaped_size = MmapedSize;
43   proc_maps->len = Size;
44 }
45 
46 bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
47   if (Error()) return false; // simulate empty maps
48   char *last = data_.proc_self_maps.data + data_.proc_self_maps.len;
49   if (data_.current >= last) return false;
50 
51   prxmap_t *xmapentry =
52       const_cast<prxmap_t *>(reinterpret_cast<const prxmap_t *>(data_.current));
53 
54   segment->start = (uptr)xmapentry->pr_vaddr;
55   segment->end = (uptr)(xmapentry->pr_vaddr + xmapentry->pr_size);
56   segment->offset = (uptr)xmapentry->pr_offset;
57 
58   segment->protection = 0;
59   if ((xmapentry->pr_mflags & MA_READ) != 0)
60     segment->protection |= kProtectionRead;
61   if ((xmapentry->pr_mflags & MA_WRITE) != 0)
62     segment->protection |= kProtectionWrite;
63   if ((xmapentry->pr_mflags & MA_EXEC) != 0)
64     segment->protection |= kProtectionExecute;
65   if ((xmapentry->pr_mflags & MA_SHARED) != 0)
66     segment->protection |= kProtectionShared;
67 
68   if (segment->filename != NULL && segment->filename_size > 0) {
69     char proc_path[PATH_MAX + 1];
70 
71     // Avoid unnecessary readlink on unnamed entires.
72     if (xmapentry->pr_mapname[0] == '\0')
73       segment->filename[0] = '\0';
74     else {
75       internal_snprintf(proc_path, sizeof(proc_path), "/proc/self/path/%s",
76                         xmapentry->pr_mapname);
77       ssize_t sz = internal_readlink(proc_path, segment->filename,
78                                      segment->filename_size - 1);
79 
80       // If readlink failed, the map is anonymous.
81       if (sz == -1)
82         segment->filename[0] = '\0';
83       else if ((size_t)sz < segment->filename_size)
84         // readlink doesn't NUL-terminate.
85         segment->filename[sz] = '\0';
86     }
87   }
88 
89   data_.current += sizeof(prxmap_t);
90 
91   return true;
92 }
93 
94 }  // namespace __sanitizer
95 
96 #endif  // SANITIZER_SOLARIS
97