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