1 //===-- bytemap.h -----------------------------------------------*- C++ -*-===// 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 #ifndef SCUDO_BYTEMAP_H_ 10 #define SCUDO_BYTEMAP_H_ 11 12 #include "atomic_helpers.h" 13 #include "common.h" 14 #include "mutex.h" 15 16 namespace scudo { 17 18 template <uptr Size> class FlatByteMap { 19 public: 20 void initLinkerInitialized() { 21 Map = reinterpret_cast<u8 *>(map(nullptr, Size, "scudo:bytemap")); 22 } 23 void init() { initLinkerInitialized(); } 24 25 void unmapTestOnly() { unmap(reinterpret_cast<void *>(Map), Size); } 26 27 void set(uptr Index, u8 Value) { 28 DCHECK_LT(Index, Size); 29 DCHECK_EQ(0U, Map[Index]); 30 Map[Index] = Value; 31 } 32 u8 operator[](uptr Index) { 33 DCHECK_LT(Index, Size); 34 return Map[Index]; 35 } 36 37 private: 38 u8 *Map; 39 }; 40 41 template <uptr Level1Size, uptr Level2Size> class TwoLevelByteMap { 42 public: 43 void initLinkerInitialized() { 44 Level1Map = reinterpret_cast<atomic_uptr *>( 45 map(nullptr, sizeof(atomic_uptr) * Level1Size, "scudo:bytemap")); 46 } 47 void init() { 48 Mutex.init(); 49 initLinkerInitialized(); 50 } 51 52 void reset() { 53 for (uptr I = 0; I < Level1Size; I++) { 54 u8 *P = get(I); 55 if (!P) 56 continue; 57 unmap(P, Level2Size); 58 } 59 memset(Level1Map, 0, sizeof(atomic_uptr) * Level1Size); 60 } 61 62 void unmapTestOnly() { 63 reset(); 64 unmap(reinterpret_cast<void *>(Level1Map), 65 sizeof(atomic_uptr) * Level1Size); 66 } 67 68 uptr size() const { return Level1Size * Level2Size; } 69 70 void set(uptr Index, u8 Value) { 71 DCHECK_LT(Index, Level1Size * Level2Size); 72 u8 *Level2Map = getOrCreate(Index / Level2Size); 73 DCHECK_EQ(0U, Level2Map[Index % Level2Size]); 74 Level2Map[Index % Level2Size] = Value; 75 } 76 77 u8 operator[](uptr Index) const { 78 DCHECK_LT(Index, Level1Size * Level2Size); 79 u8 *Level2Map = get(Index / Level2Size); 80 if (!Level2Map) 81 return 0; 82 return Level2Map[Index % Level2Size]; 83 } 84 85 private: 86 u8 *get(uptr Index) const { 87 DCHECK_LT(Index, Level1Size); 88 return reinterpret_cast<u8 *>( 89 atomic_load(&Level1Map[Index], memory_order_acquire)); 90 } 91 92 u8 *getOrCreate(uptr Index) { 93 u8 *Res = get(Index); 94 if (!Res) { 95 ScopedLock L(Mutex); 96 if (!(Res = get(Index))) { 97 Res = reinterpret_cast<u8 *>(map(nullptr, Level2Size, "scudo:bytemap")); 98 atomic_store(&Level1Map[Index], reinterpret_cast<uptr>(Res), 99 memory_order_release); 100 } 101 } 102 return Res; 103 } 104 105 atomic_uptr *Level1Map; 106 HybridMutex Mutex; 107 }; 108 109 } // namespace scudo 110 111 #endif // SCUDO_BYTEMAP_H_ 112