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