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