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, ¤tRegContext_, 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(¤tRegContext_, 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(¤tRegContext_, 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(¤tRegContext_, 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(¤tRegContext_, 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