• 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_ABSINT_EXEC_CONTEXT_HPP_
17 #define PANDA_VERIFIER_ABSINT_EXEC_CONTEXT_HPP_
18 
19 #include "reg_context.h"
20 
21 #include "util/addr_map.h"
22 #include "util/hash.h"
23 
24 #include "include/mem/panda_containers.h"
25 
26 namespace panda::verifier {
27 
28 enum class EntryPointType : size_t { METHOD_BODY, EXCEPTION_HANDLER, __LAST__ = EXCEPTION_HANDLER };
29 
30 class ExecContext {
31 public:
32     enum class Status { OK, ALL_DONE, NO_ENTRY_POINTS_WITH_CONTEXT };
33 
HasContext(const uint8_t * addr)34     bool HasContext(const uint8_t *addr) const
35     {
36         return RegContextOnCheckPoint_.count(addr) > 0;
37     }
38 
IsCheckPoint(const uint8_t * addr)39     bool IsCheckPoint(const uint8_t *addr) const
40     {
41         return CheckPoint_.HasMark(addr);
42     }
43 
AddEntryPoint(const uint8_t * addr,EntryPointType type)44     void AddEntryPoint(const uint8_t *addr, EntryPointType type)
45     {
46         EntryPoint_.insert({addr, type});
47     }
48 
49     template <typename Reporter>
StoreCurrentRegContextForAddr(const uint8_t * addr,Reporter reporter)50     void StoreCurrentRegContextForAddr(const uint8_t *addr, Reporter reporter)
51     {
52         if (HasContext(addr)) {
53             StoreCurrentRegContextForAddrIfHasContext(addr, reporter);
54         } else if (IsCheckPoint(addr)) {
55             RegContextOnCheckPoint_[addr] = CurrentRegContext_;
56         }
57     }
58 
59     template <typename Reporter>
StoreCurrentRegContextForAddrIfHasContext(const uint8_t * addr,Reporter reporter)60     void StoreCurrentRegContextForAddrIfHasContext(const uint8_t *addr, Reporter reporter)
61     {
62         RegContext &ctx = RegContextOnCheckPoint_[addr];
63         auto lub = ctx & CurrentRegContext_;
64 
65         if (lub.HasInconsistentRegs()) {
66             for (int reg_idx : lub.InconsistentRegsNums()) {
67                 if (!reporter(reg_idx, CurrentRegContext_[reg_idx], ctx[reg_idx])) {
68                     break;
69                 }
70             }
71         }
72 
73         ctx &= CurrentRegContext_;
74 
75         if (ctx.HasInconsistentRegs()) {
76             ctx.RemoveInconsistentRegs();
77         }
78     }
79 
StoreCurrentRegContextForAddr(const uint8_t * addr)80     void StoreCurrentRegContextForAddr(const uint8_t *addr)
81     {
82         if (HasContext(addr)) {
83             RegContext &ctx = RegContextOnCheckPoint_[addr];
84             ctx &= CurrentRegContext_;
85             ctx.RemoveInconsistentRegs();
86         } else if (IsCheckPoint(addr)) {
87             RegContextOnCheckPoint_[addr] = CurrentRegContext_;
88         }
89     }
90 
91     template <typename Reporter>
ProcessJump(const uint8_t * jmpInsnPtr,const uint8_t * targetPtr,Reporter reporter,EntryPointType codeType)92     void ProcessJump(const uint8_t *jmpInsnPtr, const uint8_t *targetPtr, Reporter reporter, EntryPointType codeType)
93     {
94         if (!ProcessedJumps_.HasMark(jmpInsnPtr)) {
95             ProcessedJumps_.Mark(jmpInsnPtr);
96             AddEntryPoint(targetPtr, codeType);
97             StoreCurrentRegContextForAddr(targetPtr, reporter);
98         }
99     }
100 
ProcessJump(const uint8_t * jmpInsnPtr,const uint8_t * targetPtr,EntryPointType codeType)101     void ProcessJump(const uint8_t *jmpInsnPtr, const uint8_t *targetPtr, EntryPointType codeType)
102     {
103         if (!ProcessedJumps_.HasMark(jmpInsnPtr)) {
104             ProcessedJumps_.Mark(jmpInsnPtr);
105             AddEntryPoint(targetPtr, codeType);
106             StoreCurrentRegContextForAddr(targetPtr);
107         }
108     }
109 
RegContextOnTarget(const uint8_t * addr)110     const RegContext &RegContextOnTarget(const uint8_t *addr) const
111     {
112         auto ctx = RegContextOnCheckPoint_.find(addr);
113         ASSERT(ctx != RegContextOnCheckPoint_.cend());
114         return ctx->second;
115     }
116 
GetEntryPointForChecking(const uint8_t ** entry,EntryPointType * entryType)117     Status GetEntryPointForChecking(const uint8_t **entry, EntryPointType *entryType)
118     {
119         for (auto [addr, type] : EntryPoint_) {
120             if (HasContext(addr)) {
121                 *entry = addr;
122                 *entryType = type;
123                 CurrentRegContext_ = RegContextOnTarget(addr);
124                 EntryPoint_.erase({addr, type});
125                 return Status::OK;
126             }
127         }
128         if (EntryPoint_.empty()) {
129             return Status::ALL_DONE;
130         }
131         return Status::NO_ENTRY_POINTS_WITH_CONTEXT;
132     }
133 
CurrentRegContext()134     RegContext &CurrentRegContext()
135     {
136         return CurrentRegContext_;
137     }
138 
CurrentRegContext()139     const RegContext &CurrentRegContext() const
140     {
141         return CurrentRegContext_;
142     }
143 
SetCheckPoint(const uint8_t * addr)144     void SetCheckPoint(const uint8_t *addr)
145     {
146         CheckPoint_.Mark(addr);
147     }
148 
SetTypecastPoint(const uint8_t * addr)149     void SetTypecastPoint(const uint8_t *addr)
150     {
151         CheckPoint_.Mark(addr);
152         TypecastPoint_.Mark(addr);
153     }
154 
IsTypecastPoint(const uint8_t * addr)155     bool IsTypecastPoint(const uint8_t *addr) const
156     {
157         return TypecastPoint_.HasMark(addr);
158     }
159 
160     template <typename Handler>
ForAllTypesOfRegAccordingToTypecasts(int reg,const RegContext & ctx,Handler && handler)161     void ForAllTypesOfRegAccordingToTypecasts(int reg, const RegContext &ctx, Handler &&handler)
162     {
163         if (ctx.IsRegDefined(reg)) {
164             const auto &atv = ctx[reg];
165             if (!handler(atv)) {
166                 return;
167             }
168             const auto &origin = atv.GetOrigin();
169             if (origin.IsValid() && !origin.AtStart()) {
170                 uint32_t offset = origin.GetOffset();
171                 const uint8_t *ptr = &(TypecastPoint_.AddrStart<const uint8_t *>()[offset]);  // NOLINT
172                 if (IsTypecastPoint(ptr)) {
173                     ForAllTypesOfRegAccordingToTypecasts(reg, RegContextOnTarget(ptr), std::move(handler));
174                 }
175             }
176         }
177     }
178 
179     template <typename Fetcher>
SetCheckPoints(Fetcher fetcher)180     void SetCheckPoints(Fetcher fetcher)
181     {
182         while (auto tgt = fetcher()) {
183             SetCheckPoint(*tgt);
184         }
185     }
186 
187     template <typename Handler>
ForContextsOnCheckPointsInRange(const uint8_t * from,const uint8_t * to,Handler handler)188     void ForContextsOnCheckPointsInRange(const uint8_t *from, const uint8_t *to, Handler handler)
189     {
190         CheckPoint_.EnumerateMarksInScope<const uint8_t *>(from, to, [&handler, this](const uint8_t *ptr) {
191             if (HasContext(ptr)) {
192                 return handler(ptr, RegContextOnCheckPoint_[ptr]);
193             }
194             return true;
195         });
196     }
197 
ExecContext(const uint8_t * pcStartPtr,const uint8_t * pcEndPtr)198     ExecContext(const uint8_t *pcStartPtr, const uint8_t *pcEndPtr)
199         : CheckPoint_ {pcStartPtr, pcEndPtr},
200           ProcessedJumps_ {pcStartPtr, pcEndPtr},
201           TypecastPoint_ {pcStartPtr, pcEndPtr}
202     {
203     }
204 
205     DEFAULT_MOVE_SEMANTIC(ExecContext);
206     ExecContext(const ExecContext &) = default;
207     ~ExecContext() = default;
208 
209 private:
210     AddrMap CheckPoint_;
211     AddrMap ProcessedJumps_;
212     AddrMap TypecastPoint_;
213     PandaUnorderedSet<std::pair<const uint8_t *, EntryPointType>> EntryPoint_;
214     PandaUnorderedMap<const uint8_t *, RegContext> RegContextOnCheckPoint_;
215     RegContext CurrentRegContext_;
216 };
217 }  // namespace panda::verifier
218 
219 #endif  // !PANDA_VERIFIER_ABSINT_EXEC_CONTEXT_HPP_
220