| 1 | //===-- sanitizer_procmaps_linux.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 (Linux-specific parts). |
| 10 | //===----------------------------------------------------------------------===// |
| 11 | |
| 12 | #include "sanitizer_platform.h" |
| 13 | #if SANITIZER_LINUX |
| 14 | #include "sanitizer_common.h" |
| 15 | #include "sanitizer_procmaps.h" |
| 16 | |
| 17 | namespace __sanitizer { |
| 18 | |
| 19 | void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { |
| 20 | if (!ReadFileToBuffer(file_name: "/proc/self/maps" , buff: &proc_maps->data, |
| 21 | buff_size: &proc_maps->mmaped_size, read_len: &proc_maps->len)) { |
| 22 | proc_maps->data = nullptr; |
| 23 | proc_maps->mmaped_size = 0; |
| 24 | proc_maps->len = 0; |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | static bool IsOneOf(char c, char c1, char c2) { |
| 29 | return c == c1 || c == c2; |
| 30 | } |
| 31 | |
| 32 | bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { |
| 33 | if (Error()) return false; // simulate empty maps |
| 34 | char *last = data_.proc_self_maps.data + data_.proc_self_maps.len; |
| 35 | if (data_.current >= last) return false; |
| 36 | char *next_line = |
| 37 | (char *)internal_memchr(s: data_.current, c: '\n', n: last - data_.current); |
| 38 | if (next_line == 0) |
| 39 | next_line = last; |
| 40 | // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar |
| 41 | segment->start = ParseHex(p: &data_.current); |
| 42 | CHECK_EQ(*data_.current++, '-'); |
| 43 | segment->end = ParseHex(p: &data_.current); |
| 44 | CHECK_EQ(*data_.current++, ' '); |
| 45 | CHECK(IsOneOf(*data_.current, '-', 'r')); |
| 46 | segment->protection = 0; |
| 47 | if (*data_.current++ == 'r') segment->protection |= kProtectionRead; |
| 48 | CHECK(IsOneOf(*data_.current, '-', 'w')); |
| 49 | if (*data_.current++ == 'w') segment->protection |= kProtectionWrite; |
| 50 | CHECK(IsOneOf(*data_.current, '-', 'x')); |
| 51 | if (*data_.current++ == 'x') segment->protection |= kProtectionExecute; |
| 52 | CHECK(IsOneOf(*data_.current, 's', 'p')); |
| 53 | if (*data_.current++ == 's') segment->protection |= kProtectionShared; |
| 54 | CHECK_EQ(*data_.current++, ' '); |
| 55 | segment->offset = ParseHex(p: &data_.current); |
| 56 | CHECK_EQ(*data_.current++, ' '); |
| 57 | ParseHex(p: &data_.current); |
| 58 | CHECK_EQ(*data_.current++, ':'); |
| 59 | ParseHex(p: &data_.current); |
| 60 | CHECK_EQ(*data_.current++, ' '); |
| 61 | while (IsDecimal(c: *data_.current)) data_.current++; |
| 62 | // Qemu may lack the trailing space. |
| 63 | // https://github.com/google/sanitizers/issues/160 |
| 64 | // CHECK_EQ(*data_.current++, ' '); |
| 65 | // Skip spaces. |
| 66 | while (data_.current < next_line && *data_.current == ' ') data_.current++; |
| 67 | // Fill in the filename. |
| 68 | if (segment->filename) { |
| 69 | uptr len = |
| 70 | Min(a: (uptr)(next_line - data_.current), b: segment->filename_size - 1); |
| 71 | internal_strncpy(dst: segment->filename, src: data_.current, n: len); |
| 72 | segment->filename[len] = 0; |
| 73 | } |
| 74 | |
| 75 | data_.current = next_line + 1; |
| 76 | return true; |
| 77 | } |
| 78 | |
| 79 | } // namespace __sanitizer |
| 80 | |
| 81 | #endif // SANITIZER_LINUX |
| 82 | |