• 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 = RcUnion(&ctx, &currentRegContext_, typeSystem_);
64         if (lub.HasInconsistentRegs()) {
65             for (int regIdx : lub.InconsistentRegsNums()) {
66                 if (!reporter(regIdx, currentRegContext_[regIdx], ctx[regIdx])) {
67                     break;
68                 }
69             }
70         }
71 
72         ctx.UnionWith(&currentRegContext_, typeSystem_);
73 
74         if (ctx.HasInconsistentRegs()) {
75             ctx.RemoveInconsistentRegs();
76         }
77     }
78 
StoreCurrentRegContextForAddr(const uint8_t * addr)79     void StoreCurrentRegContextForAddr(const uint8_t *addr)
80     {
81         if (HasContext(addr)) {
82             RegContext &ctx = regContextOnCheckPoint_[addr];
83             ctx.UnionWith(&currentRegContext_, typeSystem_);
84             ctx.RemoveInconsistentRegs();
85         } else if (IsCheckPoint(addr)) {
86             regContextOnCheckPoint_[addr] = currentRegContext_;
87         }
88     }
89 
90     template <typename Reporter>
ProcessJump(const uint8_t * jmpInsnPtr,const uint8_t * targetPtr,Reporter reporter,EntryPointType codeType)91     void ProcessJump(const uint8_t *jmpInsnPtr, const uint8_t *targetPtr, Reporter reporter, EntryPointType codeType)
92     {
93         if (!processedJumps_.HasMark(jmpInsnPtr)) {
94             processedJumps_.Mark(jmpInsnPtr);
95             AddEntryPoint(targetPtr, codeType);
96             StoreCurrentRegContextForAddr(targetPtr, reporter);
97         } else {
98             RegContext &targetCtx = regContextOnCheckPoint_[targetPtr];
99             bool typeUpdated = targetCtx.UnionWith(&currentRegContext_, typeSystem_);
100             if (typeUpdated) {
101                 AddEntryPoint(targetPtr, codeType);
102             }
103         }
104     }
105 
ProcessJump(const uint8_t * jmpInsnPtr,const uint8_t * targetPtr,EntryPointType codeType)106     void ProcessJump(const uint8_t *jmpInsnPtr, const uint8_t *targetPtr, EntryPointType codeType)
107     {
108         if (!processedJumps_.HasMark(jmpInsnPtr)) {
109             processedJumps_.Mark(jmpInsnPtr);
110             AddEntryPoint(targetPtr, codeType);
111             StoreCurrentRegContextForAddr(targetPtr);
112         } else {
113             RegContext &targetCtx = regContextOnCheckPoint_[targetPtr];
114             bool typeUpdated = targetCtx.UnionWith(&currentRegContext_, typeSystem_);
115             if (typeUpdated) {
116                 AddEntryPoint(targetPtr, codeType);
117             }
118         }
119     }
120 
RegContextOnTarget(const uint8_t * addr)121     const RegContext &RegContextOnTarget(const uint8_t *addr) const
122     {
123         auto ctx = regContextOnCheckPoint_.find(addr);
124         ASSERT(ctx != regContextOnCheckPoint_.cend());
125         return ctx->second;
126     }
127 
GetEntryPointForChecking(const uint8_t ** entry,EntryPointType * entryType)128     Status GetEntryPointForChecking(const uint8_t **entry, EntryPointType *entryType)
129     {
130         for (auto [addr, type] : entryPoint_) {
131             if (HasContext(addr)) {
132                 *entry = addr;
133                 *entryType = type;
134                 currentRegContext_ = RegContextOnTarget(addr);
135                 entryPoint_.erase({addr, type});
136                 return Status::OK;
137             }
138         }
139         if (entryPoint_.empty()) {
140             return Status::ALL_DONE;
141         }
142         return Status::NO_ENTRY_POINTS_WITH_CONTEXT;
143     }
144 
CurrentRegContext()145     RegContext &CurrentRegContext()
146     {
147         return currentRegContext_;
148     }
149 
CurrentRegContext()150     const RegContext &CurrentRegContext() const
151     {
152         return currentRegContext_;
153     }
154 
SetCheckPoint(const uint8_t * addr)155     void SetCheckPoint(const uint8_t *addr)
156     {
157         checkPoint_.Mark(addr);
158     }
159 
160     template <typename Fetcher>
SetCheckPoints(Fetcher fetcher)161     void SetCheckPoints(Fetcher fetcher)
162     {
163         while (auto tgt = fetcher()) {
164             SetCheckPoint(*tgt);
165         }
166     }
167 
168     template <typename Handler>
ForContextsOnCheckPointsInRange(const uint8_t * from,const uint8_t * to,Handler handler)169     void ForContextsOnCheckPointsInRange(const uint8_t *from, const uint8_t *to, Handler handler)
170     {
171         checkPoint_.EnumerateMarksInScope<const uint8_t *>(from, to, [&handler, this](const uint8_t *ptr) {
172             if (HasContext(ptr)) {
173                 return handler(ptr, regContextOnCheckPoint_[ptr]);
174             }
175             return true;
176         });
177     }
178 
ExecContext(const uint8_t * pcStartPtr,const uint8_t * pcEndPtr,TypeSystem * typeSystem)179     ExecContext(const uint8_t *pcStartPtr, const uint8_t *pcEndPtr, TypeSystem *typeSystem)
180         : checkPoint_ {pcStartPtr, pcEndPtr}, processedJumps_ {pcStartPtr, pcEndPtr}, typeSystem_ {typeSystem}
181     {
182     }
183 
184     DEFAULT_MOVE_SEMANTIC(ExecContext);
185     DEFAULT_COPY_SEMANTIC(ExecContext);
186     ~ExecContext() = default;
187 
188 private:
189     AddrMap checkPoint_;
190     AddrMap processedJumps_;
191     // Use an ordered set to make iteration over elements reproducible.
192     PandaSet<std::pair<const uint8_t *, EntryPointType>> entryPoint_;
193     PandaUnorderedMap<const uint8_t *, RegContext> regContextOnCheckPoint_;
194     TypeSystem *typeSystem_;
195     RegContext currentRegContext_;
196 };
197 }  // namespace panda::verifier
198 
199 #endif  // !PANDA_VERIFIER_ABSINT_EXEC_CONTEXT_HPP
200