• 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#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