1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef _PANDA_VERIFIER_ADDR_MAP_HPP_ 17 #define _PANDA_VERIFIER_ADDR_MAP_HPP_ 18 19 #include "macros.h" 20 #include "range.h" 21 #include "bit_vector.h" 22 23 #include <cstdint> 24 25 namespace panda::verifier { 26 class AddrMap { 27 public: 28 AddrMap() = delete; AddrMap(const void * start_ptr,const void * end_ptr)29 AddrMap(const void *start_ptr, const void *end_ptr) 30 : AddrMap(reinterpret_cast<uintptr_t>(start_ptr), reinterpret_cast<uintptr_t>(end_ptr)) 31 { 32 } 33 AddrMap(const void * start_ptr,size_t size)34 AddrMap(const void *start_ptr, size_t size) 35 : AddrMap(reinterpret_cast<uintptr_t>(start_ptr), reinterpret_cast<uintptr_t>(start_ptr) + size - 1) 36 { 37 } 38 39 ~AddrMap() = default; 40 IsInAddressSpace(const void * ptr)41 bool IsInAddressSpace(const void *ptr) const 42 { 43 return IsInAddressSpace(reinterpret_cast<uintptr_t>(ptr)); 44 } 45 46 template <typename PtrType> AddrStart()47 PtrType AddrStart() const 48 { 49 return reinterpret_cast<PtrType>(AddrRange_.Start()); 50 } 51 52 template <typename PtrType> AddrEnd()53 PtrType AddrEnd() const 54 { 55 return reinterpret_cast<PtrType>(AddrRange_.End()); 56 } 57 Mark(const void * addr_ptr)58 bool Mark(const void *addr_ptr) 59 { 60 return Mark(addr_ptr, addr_ptr); 61 } 62 Mark(const void * addr_start_ptr,const void * addr_end_ptr)63 bool Mark(const void *addr_start_ptr, const void *addr_end_ptr) 64 { 65 return Mark(reinterpret_cast<uintptr_t>(addr_start_ptr), reinterpret_cast<uintptr_t>(addr_end_ptr)); 66 } 67 Clear()68 void Clear() 69 { 70 Clear(AddrRange_.Start(), AddrRange_.End()); 71 } 72 Clear(const void * addr_ptr)73 bool Clear(const void *addr_ptr) 74 { 75 return Clear(addr_ptr, addr_ptr); 76 } 77 Clear(const void * addr_start_ptr,const void * addr_end_ptr)78 bool Clear(const void *addr_start_ptr, const void *addr_end_ptr) 79 { 80 return Clear(reinterpret_cast<uintptr_t>(addr_start_ptr), reinterpret_cast<uintptr_t>(addr_end_ptr)); 81 } 82 HasMark(const void * addr_ptr)83 bool HasMark(const void *addr_ptr) const 84 { 85 return HasMarks(addr_ptr, addr_ptr); 86 } 87 HasMarks(const void * addr_start_ptr,const void * addr_end_ptr)88 bool HasMarks(const void *addr_start_ptr, const void *addr_end_ptr) const 89 { 90 return HasMarks(reinterpret_cast<uintptr_t>(addr_start_ptr), reinterpret_cast<uintptr_t>(addr_end_ptr)); 91 } 92 HasCommonMarks(const AddrMap & rhs)93 bool HasCommonMarks(const AddrMap &rhs) const 94 { 95 // todo: work with different addr spaces 96 ASSERT(AddrRange_ == rhs.AddrRange_); 97 return BitVector::lazy_and_then_indices_of<true>(BitMap_, rhs.BitMap_)().IsValid(); 98 } 99 100 template <typename PtrType> GetFirstCommonMark(const AddrMap & rhs,PtrType * ptr)101 bool GetFirstCommonMark(const AddrMap &rhs, PtrType *ptr) const 102 { 103 // todo: work with different addr spaces 104 ASSERT(AddrRange_ == rhs.AddrRange_); 105 Index<size_t> idx = BitVector::lazy_and_then_indices_of<true>(BitMap_, rhs.BitMap_)(); 106 if (idx.IsValid()) { 107 size_t offset = idx; 108 *ptr = reinterpret_cast<PtrType>(AddrRange_.IndexOf(offset)); 109 return true; 110 } 111 return false; 112 } 113 114 // TODO(vdyadov): optimize this function, push blocks enumeration to bit vector level 115 // and refactor it to work with words and ctlz like intrinsics 116 template <typename PtrType, typename Callback> EnumerateMarkedBlocks(Callback cb)117 void EnumerateMarkedBlocks(Callback cb) const 118 { 119 PtrType start = nullptr; 120 PtrType end = nullptr; 121 for (const auto addr : AddrRange_) { 122 uintptr_t bit_offset = AddrRange_.OffsetOf(addr); 123 if (start == nullptr) { 124 if (BitMap_[bit_offset]) { 125 start = reinterpret_cast<PtrType>(addr); 126 } 127 } else { 128 if (BitMap_[bit_offset]) { 129 continue; 130 } 131 end = reinterpret_cast<PtrType>(addr - 1); 132 if (!cb(start, end)) { 133 return; 134 } 135 start = nullptr; 136 } 137 } 138 if (start != nullptr) { 139 end = reinterpret_cast<PtrType>(AddrRange_.End()); 140 cb(start, end); 141 } 142 } 143 InvertMarks()144 void InvertMarks() 145 { 146 BitMap_.invert(); 147 } 148 149 template <typename PtrType, typename Handler> EnumerateMarksInScope(const void * addr_start_ptr,const void * addr_end_ptr,Handler handler)150 void EnumerateMarksInScope(const void *addr_start_ptr, const void *addr_end_ptr, Handler handler) const 151 { 152 EnumerateMarksInScope<PtrType>(reinterpret_cast<uintptr_t>(addr_start_ptr), 153 reinterpret_cast<uintptr_t>(addr_end_ptr), std::move(handler)); 154 } 155 156 private: AddrMap(uintptr_t addr_from,uintptr_t addr_to)157 AddrMap(uintptr_t addr_from, uintptr_t addr_to) : AddrRange_ {addr_from, addr_to}, BitMap_ {AddrRange_.Length()} {} 158 IsInAddressSpace(uintptr_t addr)159 bool IsInAddressSpace(uintptr_t addr) const 160 { 161 return AddrRange_.Contains(addr); 162 } 163 Mark(uintptr_t addr_from,uintptr_t addr_to)164 bool Mark(uintptr_t addr_from, uintptr_t addr_to) 165 { 166 if (!AddrRange_.Contains(addr_from) || !AddrRange_.Contains(addr_to)) { 167 return false; 168 } 169 ASSERT(addr_from <= addr_to); 170 BitMap_.Set(AddrRange_.OffsetOf(addr_from), AddrRange_.OffsetOf(addr_to)); 171 return true; 172 } 173 Clear(uintptr_t addr_from,uintptr_t addr_to)174 bool Clear(uintptr_t addr_from, uintptr_t addr_to) 175 { 176 if (!AddrRange_.Contains(addr_from) || !AddrRange_.Contains(addr_to)) { 177 return false; 178 } 179 ASSERT(addr_from <= addr_to); 180 BitMap_.Clr(AddrRange_.OffsetOf(addr_from), AddrRange_.OffsetOf(addr_to)); 181 return true; 182 } 183 HasMarks(uintptr_t addr_from,uintptr_t addr_to)184 bool HasMarks(uintptr_t addr_from, uintptr_t addr_to) const 185 { 186 if (!AddrRange_.Contains(addr_from) || !AddrRange_.Contains(addr_to)) { 187 return false; 188 } 189 ASSERT(addr_from <= addr_to); 190 Index<size_t> first_mark_idx = 191 BitMap_.LazyIndicesOf<1>(AddrRange_.OffsetOf(addr_from), AddrRange_.OffsetOf(addr_to))(); 192 return first_mark_idx.IsValid(); 193 } 194 195 template <typename PtrType, typename Handler> EnumerateMarksInScope(uintptr_t addr_from,uintptr_t addr_to,Handler handler)196 void EnumerateMarksInScope(uintptr_t addr_from, uintptr_t addr_to, Handler handler) const 197 { 198 addr_from = AddrRange_.PutInBounds(addr_from); 199 addr_to = AddrRange_.PutInBounds(addr_to); 200 ASSERT(addr_from <= addr_to); 201 auto mark_idxs = BitMap_.LazyIndicesOf<1>(AddrRange_.OffsetOf(addr_from), AddrRange_.OffsetOf(addr_to)); 202 Index<size_t> idx = mark_idxs(); 203 while (idx.IsValid()) { 204 auto addr = AddrRange_.IndexOf(idx); 205 PtrType ptr = reinterpret_cast<PtrType>(addr); 206 if (!handler(ptr)) { 207 return; 208 } 209 idx = mark_idxs(); 210 } 211 } 212 213 private: 214 Range<uintptr_t> AddrRange_; 215 BitVector BitMap_; 216 }; 217 } // namespace panda::verifier 218 219 #endif // !_PANDA_VERIFIER_ADDR_MAP_HPP_ 220