• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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