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#include "verification/jobs/thread_pool.h" 17 18namespace panda::verifier { 19 20#define LOG_INST() \ 21 LOG(DEBUG, VERIFIER) << "JOBFILL: " << std::hex << std::setw(sizeof(inst.GetOffset())) << std::setfill('0') \ 22 << inst.GetOffset() << std::dec << ": " << inst 23 24// NOLINTNEXTLINE(readability-function-size) 25bool Job::ResolveIdentifiers(LibCache &cache) { 26#if defined(__clang__) 27#pragma clang diagnostic push 28#pragma clang diagnostic ignored "-Wvoid-ptr-dereference" 29#pragma clang diagnostic ignored "-Wgnu-label-as-value" 30#elif defined(__GNUC__) 31#pragma GCC diagnostic push 32#pragma GCC diagnostic ignored "-Wpedantic" 33#endif 34 35 LOG(DEBUG, VERIFIER) << "JOBFILL: Filling Job cache for method '" << cached_method_.GetName() << "'"; 36 37 std::array<const void*, <%= Panda::dispatch_table.handler_names.size %>> dispatch_table{ 38% Panda::dispatch_table.handler_names.each do |name| 39 &&HANDLE_<%= name %>, 40% end 41 }; 42 43 // ASSERT method_.bytecode == cached_method_.bytecode 44 const uint8_t *start = cached_method_.bytecode; 45 size_t code_size = cached_method_.bytecode_size; 46 ASSERT(start == method_.GetInstructions()); 47 ASSERT(code_size == method_.GetCodeSize()); 48 const uint8_t *end = &start[code_size - 1]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 49 50 BytecodeInstructionSafe inst{start, start, end}; 51 uint8_t secondary_opcode; 52 53 if (!inst.IsPrimaryOpcodeValid()) { 54 LOG(ERROR, VERIFIER) << "Incorrect opcode"; 55 return false; 56 } 57 goto* dispatch_table[inst.GetPrimaryOpcode()]; 58 59% Panda::instructions.each do |i| 60% mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join 61HANDLE_<%= i.opcode.upcase %>: 62 { 63% if i.properties.any? { |prop| ['method_id', 'field_id', 'type_id', 'literalarray_id'].include?(prop) } 64 LOG_INST(); 65 auto id = inst.GetId(); 66% end 67% if (['method_id', 'field_id', 'type_id', 'string_id', 'literalarray_id'] & i.properties).size > 1 68% cache_api = "cache_api" 69 auto cache_api = cache.FastAPI(); 70% else 71% cache_api = "cache.FastAPI()" 72% end 73% if i.properties.include?('literalarray_id') 74 auto src_lang = cached_method_.GetSourceLang(); 75 const auto& pf = *cached_method_.file; 76 panda_file::LiteralTag tag; 77 panda_file::LiteralDataAccessor::LiteralValue value; 78 if (!Runtime::GetLiteralTagAndValue(pf, id.AsFileId().GetOffset(), &tag, &value)) { 79 LOG(DEBUG, VERIFIER) << "JOBFILL: Cannot get literal tag with id=" << std::hex << id << " for offset 0x" << std::hex << inst.GetOffset(); 80 } else { 81 OptionalConstRef<LibCache::CachedClass> cached_class; 82 auto resolve_and_link = [&](const char *descr) { 83 cached_class = <%= cache_api %>.ResolveAndLink(src_lang, utf::CStringAsMutf8(descr)); 84 }; 85 // descriptors for primitive types get from libpandafile/templates/type 86 switch (tag) { 87 case panda_file::LiteralTag::ARRAY_U1: 88 resolve_and_link("[Z"); 89 break; 90 case panda_file::LiteralTag::ARRAY_U8: 91 resolve_and_link("[H"); 92 break; 93 case panda_file::LiteralTag::ARRAY_I8: 94 resolve_and_link("[B"); 95 break; 96 case panda_file::LiteralTag::ARRAY_I16: 97 resolve_and_link("[S"); 98 break; 99 case panda_file::LiteralTag::ARRAY_U16: 100 resolve_and_link("[C"); 101 break; 102 case panda_file::LiteralTag::ARRAY_U32: 103 resolve_and_link("[U"); 104 break; 105 case panda_file::LiteralTag::ARRAY_I32: 106 resolve_and_link("[I"); 107 break; 108 case panda_file::LiteralTag::ARRAY_U64: 109 resolve_and_link("[Q"); 110 break; 111 case panda_file::LiteralTag::ARRAY_I64: 112 resolve_and_link("[J"); 113 break; 114 case panda_file::LiteralTag::ARRAY_F32: 115 resolve_and_link("[F"); 116 break; 117 case panda_file::LiteralTag::ARRAY_F64: 118 resolve_and_link("[D"); 119 break; 120 case panda_file::LiteralTag::ARRAY_STRING: 121 cached_class = <%= cache_api %>.GetStringArrayClass(src_lang); 122 break; 123 default: 124 break; 125 } 126 if (cached_class.HasRef()) { 127 AddClass(inst.GetOffset(), cached_class.Get()); 128 } else { 129 LOG(DEBUG, VERIFIER) << "JOBFILL: Cannot find class for literal with id=" << std::hex << id << " for offset 0x" << std::hex << inst.GetOffset(); 130 } 131 } 132% end 133% if i.properties.include?('method_id') 134 auto cached_method = <%= cache_api %>.GetFromCache<LibCache::CachedMethod>(cached_method_, id.AsIndex()); 135 if (cached_method.HasRef()) { 136 AddMethod(inst.GetOffset(), cached_method.Get()); 137 AddClass(inst.GetOffset(), cached_method->klass); 138 } else { 139 LOG(DEBUG, VERIFIER) << "JOBFILL: Cannot resolve method with id " << id << " in method " 140 << cached_method_.GetName(); 141 } 142% end 143% if i.properties.include?('field_id') 144 auto cached_field = <%= cache_api %>.GetFromCache<LibCache::CachedField>(cached_method_, id.AsIndex()); 145 if (cached_field.HasRef()) { 146 AddField(inst.GetOffset(), cached_field.Get()); 147 } else { 148 LOG(DEBUG, VERIFIER) << "JOBFILL: Cannot resolve field with id " << id << " in method " 149 << cached_method_.GetName(); 150 } 151% end 152% if i.properties.include?('type_id') 153 auto cached_class = <%= cache_api %>.GetFromCache<LibCache::CachedClass>(cached_method_, id.AsIndex()); 154 if (cached_class.HasRef()) { 155 AddClass(inst.GetOffset(), cached_class.Get()); 156 } else { 157 LOG(DEBUG, VERIFIER) << "JOBFILL: Cannot resolve class with id " << id << " in method " 158 << cached_method_.GetName(); 159 } 160% end 161% if i.properties.include?('string_id') 162 // todo: check presence of string in index tables 163 auto cached_string_class = <%= cache_api %>.GetStringClass(cached_method_); 164 if (cached_string_class.HasRef()) { 165 AddClass(inst.GetOffset(), cached_string_class.Get()); 166 } else { 167 LOG(DEBUG, VERIFIER) << "JOBFILL: Cannot resolve string class in method " << cached_method_.GetName(); 168 } 169% end 170 171 if (inst.IsLast()) { 172 return true; 173 } 174 175 auto next_inst = inst.GetNext(); 176 if (!inst.IsPrimaryOpcodeValid()) { 177 LOG(DEBUG, VERIFIER) << "Opcode value is out of range. " 178 << "Current value is: " << static_cast<int>(inst.GetPrimaryOpcode()) 179 << ". Allowed value is in the interval: [0, <%= Panda::dispatch_table.invalid_non_prefixed_interval.min - 1 %>] U " 180 << "[<%= Panda::dispatch_table.invalid_non_prefixed_interval.max + 1 %>, <%= Panda::dispatch_table.invalid_prefixes_interval.min + 1 %>] U " 181 << "[<%= Panda::dispatch_table.invalid_prefixes_interval.max + 1 %>, 255]"; 182 return false; 183 } 184 if (!next_inst.IsValid()) { 185 LOG(DEBUG, VERIFIER) << "Invalid instruction. " 186 << "Offset of last valid instruction: " << inst.GetOffset() << ". " 187 << "Last valid instrution: " << inst; 188 return false; 189 } 190 inst = next_inst; 191 } 192 goto* dispatch_table[inst.GetPrimaryOpcode()]; 193% end 194HANDLE_INVALID: 195 LOG(ERROR, VERIFIER) << "Incorrect opcode"; 196 return false; 197% Panda::prefixes.each do |p| 198HANDLE_<%= p.handler_name %>: 199 secondary_opcode = inst.GetSecondaryOpcode(); 200 LOG(DEBUG, VERIFIER) << "Prefix subdispatch: " << "<%= p.name %>, " << static_cast<int32_t>(secondary_opcode); 201 202 if (secondary_opcode > <%= Panda::dispatch_table.secondary_opcode_bound(p) %> ) { 203 LOG(ERROR, VERIFIER) << "Incorrect opcode"; 204 return false; 205 } 206 goto *dispatch_table[<%= Panda::dispatch_table.secondary_opcode_offset(p) %> + secondary_opcode]; 207% end 208 209#if defined(__clang__) 210#pragma clang diagnostic pop 211#elif defined(__GNUC__) 212#pragma GCC diagnostic pop 213#endif 214} 215 216} // namespace panda::verifier