1 /*
2 * Copyright (c) 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 "abc_file.h"
17 #include "libpandabase/mem/pool_manager.h"
18 #include "libpandafile/class_data_accessor-inl.h"
19 #include "libpandafile/code_data_accessor-inl.h"
20 #include "libpandafile/method_data_accessor-inl.h"
21 #include "libpandafile/literal_data_accessor-inl.h"
22 #include "libpandafile/field_data_accessor-inl.h"
23 #include "libpandafile/module_data_accessor-inl.h"
24 #include "compiler/optimizer/ir_builder/ir_builder.h"
25 #include "bytecode_optimizer/common.h"
26 #include "bytecode_optimizer/runtime_adapter.h"
27 #include "callee_info.h"
28 #include "class.h"
29 #include "function.h"
30 #include "module_record.h"
31
32 namespace panda::defect_scan_aux {
33 using EntityId = panda_file::File::EntityId;
34 using StringData = panda_file::StringData;
35 using LiteralTag = panda_file::LiteralTag;
36 using ModuleDataAccessor = panda_file::ModuleDataAccessor;
37 using ModuleTag = panda_file::ModuleTag;
38
AbcFile(std::string_view filename, std::unique_ptr<const panda_file::File> &&panda_file)39 AbcFile::AbcFile(std::string_view filename, std::unique_ptr<const panda_file::File> &&panda_file)
40 : filename_(filename), panda_file_(std::forward<std::unique_ptr<const panda_file::File>>(panda_file))
41 {
42 PoolManager::Initialize(PoolType::MALLOC);
43 allocator_ = std::make_unique<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER);
44 local_allocator_ = std::make_unique<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
45 }
46
~AbcFile()47 AbcFile::~AbcFile()
48 {
49 PoolManager::Finalize();
50 }
51
Open(std::string_view abc_filename)52 std::unique_ptr<const AbcFile> AbcFile::Open(std::string_view abc_filename)
53 {
54 auto panda_file = panda_file::OpenPandaFile(abc_filename);
55 if (panda_file == nullptr) {
56 LOG(ERROR, DEFECT_SCAN_AUX) << "Can not open binary file '" << abc_filename << "'";
57 return nullptr;
58 }
59
60 std::unique_ptr<AbcFile> abc_file(new (std::nothrow) AbcFile(abc_filename, std::move(panda_file)));
61 if (abc_file == nullptr) {
62 LOG(ERROR, DEFECT_SCAN_AUX) << "Can not create AbcFile instance for '" << abc_filename << "'";
63 return nullptr;
64 }
65
66 abc_file->ExtractDebugInfo();
67 abc_file->ExtractModuleInfo();
68 abc_file->InitializeAllDefinedFunction();
69 abc_file->ExtractDefinedClassAndFunctionInfo();
70 abc_file->ExtractClassAndFunctionExportList();
71 return abc_file;
72 }
73
IsModule(std::string_view record_name) const74 bool AbcFile::IsModule(std::string_view record_name) const
75 {
76 if (IsMergeAbc() && record_name == "") {
77 LOG(FATAL, DEFECT_SCAN_AUX) <<
78 "For merge abc, need to specify record name to check if it has module info";
79 }
80 return GetModuleRecordByName(std::string(record_name)) != nullptr;
81 }
82
IsMergeAbc() const83 bool AbcFile::IsMergeAbc() const
84 {
85 return is_merge_abc_;
86 }
87
GetAbcFileName() const88 const std::string &AbcFile::GetAbcFileName() const
89 {
90 return filename_;
91 }
92
GetDefinedFunctionCount() const93 size_t AbcFile::GetDefinedFunctionCount() const
94 {
95 if (IsMergeAbc()) {
96 return merged_def_func_list_.size();
97 }
98 return def_func_list_.size();
99 }
100
GetDefinedClassCount() const101 size_t AbcFile::GetDefinedClassCount() const
102 {
103 if (IsMergeAbc()) {
104 return merged_def_class_list_.size();
105 }
106 return def_class_list_.size();
107 }
108
GetClassList() const109 const std::vector<std::shared_ptr<Class>> &AbcFile::GetClassList() const
110 {
111 if (IsMergeAbc()) {
112 return merged_def_class_list_;
113 }
114 return def_class_list_;
115 }
116
GetDefinedFunctionByIndex(size_t index) const117 const Function *AbcFile::GetDefinedFunctionByIndex(size_t index) const
118 {
119 if (IsMergeAbc()) {
120 ASSERT(index < merged_def_func_list_.size());
121 return merged_def_func_list_[index].get();
122 }
123 ASSERT(index < def_func_list_.size());
124 return def_func_list_[index].get();
125 }
126
127 const Function *AbcFile::GetFunctionByName(std::string_view func_name) const
128 {
129 return GetFunctionByNameImpl(func_name);
130 }
131
132 const Function *AbcFile::GetExportFunctionByExportName(std::string_view export_func_name,
133 std::string_view record_name) const
134 {
135 if (!IsModule(record_name)) {
136 return nullptr;
137 }
138
139 if (IsMergeAbc() && record_name == "") {
140 LOG(FATAL, DEFECT_SCAN_AUX) <<
141 "Failed to GetExportFunctionByExportName from merge abc, need to specify record name";
142 }
143 std::string inter_func_name = GetLocalNameByExportName(export_func_name, record_name);
144 auto export_func_list = export_func_list_;
145 if (IsMergeAbc()) {
146 const std::string record_name_str = std::string(record_name);
147 auto it = merge_export_func_map_.find(record_name_str);
148 if (it == merge_export_func_map_.end()) {
149 return nullptr;
150 }
151 export_func_list = it->second;
152 }
153 for (auto &export_func : export_func_list) {
154 const std::string &ex_func_name = export_func->GetFunctionName();
155 std::string_view no_hashtag_name = GetNameWithoutHashtag(ex_func_name, record_name);
156 if (no_hashtag_name == inter_func_name) {
157 return export_func;
158 }
159 }
160 return nullptr;
161 }
162
163 const Class *AbcFile::GetDefinedClassByIndex(size_t index) const
164 {
165 if (IsMergeAbc()) {
166 ASSERT(index < merged_def_class_list_.size());
167 return merged_def_class_list_[index].get();
168 }
169 ASSERT(index < def_class_list_.size());
170 return def_class_list_[index].get();
171 }
172
173 const Class *AbcFile::GetClassByName(std::string_view class_name) const
174 {
175 return GetClassByNameImpl(class_name);
176 }
177
178 const Class *AbcFile::GetExportClassByExportName(std::string_view export_class_name,
179 std::string_view record_name) const
180 {
181 if (!IsModule(record_name)) {
182 return nullptr;
183 }
184
185 if (IsMergeAbc() && record_name == "") {
186 LOG(FATAL, DEFECT_SCAN_AUX) <<
187 "Failed to GetExportClassByExportName from merge abc, need to specify record name";
188 }
189 if (!IsMergeAbc()) {
190 record_name = std::string(MODULE_CLASS);
191 }
192 std::string inter_class_name = GetLocalNameByExportName(export_class_name, record_name);
193 auto export_class_list = export_class_list_;
194 if (IsMergeAbc()) {
195 const std::string record_name_str = std::string(record_name);
196 auto it = merge_export_class_map_.find(record_name_str);
197 if (it == merge_export_class_map_.end()) {
198 return nullptr;
199 }
200 export_class_list = it->second;
201 }
202 for (auto export_class : export_class_list) {
203 const std::string &ex_class_name = export_class->GetClassName();
204 std::string_view no_hashtag_name = GetNameWithoutHashtag(ex_class_name, record_name);
205 if (no_hashtag_name == inter_class_name) {
206 return export_class;
207 }
208 }
209 return nullptr;
210 }
211
212 ssize_t AbcFile::GetLineNumberByInst(const Function *func, const Inst &inst) const
213 {
214 auto &line_number_table = debug_info_->GetLineNumberTable(func->GetMethodId());
215 if (!line_number_table.empty()) {
216 uint32_t inst_pc = inst.GetPc();
217 // line_number_table is in ascending order, find the element that satisfies e1.pc <= inst_pc < e2.pc
218 auto comp = [](size_t value, const panda_file::LineTableEntry &entry) { return value >= entry.offset; };
219 auto iter = std::upper_bound(line_number_table.rbegin(), line_number_table.rend(), inst_pc, comp);
220 if (iter != line_number_table.rend()) {
221 // line number written in a .abc file starts from 0
222 return iter->line + 1;
223 }
224 }
225 return -1;
226 }
227
228 const std::set<std::string> AbcFile::GetFileRecordList() const
229 {
230 return record_name_set_;
231 }
232
233 size_t AbcFile::GetFileRecordCount() const
234 {
235 return record_name_set_.size();
236 }
237
238 std::string AbcFile::GetLocalNameByExportName(std::string_view export_name, std::string_view record_name) const
239 {
240 if (!IsModule(record_name)) {
241 return EMPTY_STR;
242 }
243 if (IsMergeAbc() && record_name == "") {
244 LOG(FATAL, DEFECT_SCAN_AUX) << "Failed to GetLocalNameByExportName from merge abc, need to specify record name";
245 }
246 if (!IsMergeAbc()) {
247 record_name = std::string(MODULE_CLASS);
248 }
249 auto module_record = GetModuleRecordByName(std::string(record_name));
250 return module_record->GetLocalNameByExportName(export_name);
251 }
252
253 std::string AbcFile::GetImportNameByExportName(std::string_view export_name, std::string_view record_name) const
254 {
255 if (!IsModule(record_name)) {
256 return EMPTY_STR;
257 }
258 if (IsMergeAbc() && record_name == "") {
259 LOG(FATAL, DEFECT_SCAN_AUX)
260 << "Failed to GetImportNameByExportName from merge abc, need to specify record name";
261 }
262 if (!IsMergeAbc()) {
263 record_name = std::string(MODULE_CLASS);
264 }
265 auto module_record = GetModuleRecordByName(std::string(record_name));
266 return module_record->GetImportNameByExportName(export_name);
267 }
268
269 std::string AbcFile::GetModuleNameByExportName(std::string_view export_name, std::string_view record_name) const
270 {
271 if (!IsModule(record_name)) {
272 return EMPTY_STR;
273 }
274 if (IsMergeAbc() && record_name == "") {
275 LOG(FATAL, DEFECT_SCAN_AUX)
276 << "Failed to GetModuleNameByExportName from merge abc, need to specify record name";
277 }
278 if (!IsMergeAbc()) {
279 record_name = std::string(MODULE_CLASS);
280 }
281 auto module_record = GetModuleRecordByName(std::string(record_name));
282 return module_record->GetModuleNameByExportName(export_name);
283 }
284
285 std::string AbcFile::GetModuleNameByLocalName(std::string_view local_name, std::string_view record_name) const
286 {
287 if (!IsModule(record_name)) {
288 return EMPTY_STR;
289 }
290 if (IsMergeAbc() && record_name == "") {
291 LOG(FATAL, DEFECT_SCAN_AUX) << "Failed to GetModuleNameByLocalName from merge abc, need to specify record name";
292 }
293 if (!IsMergeAbc()) {
294 record_name = std::string(MODULE_CLASS);
295 }
296 auto module_record = GetModuleRecordByName(std::string(record_name));
297 return module_record->GetModuleNameByLocalName(local_name);
298 }
299
300 std::string AbcFile::GetImportNameByLocalName(std::string_view local_name, std::string_view record_name) const
301 {
302 if (!IsModule(record_name)) {
303 return EMPTY_STR;
304 }
305 if (IsMergeAbc() && record_name == "") {
306 LOG(FATAL, DEFECT_SCAN_AUX) << "Failed to GetImportNameByLocalName from merge abc, need to specify record name";
307 }
308 if (!IsMergeAbc()) {
309 record_name = std::string(MODULE_CLASS);
310 }
311 auto module_record = GetModuleRecordByName(std::string(record_name));
312 return module_record->GetImportNameByLocalName(local_name);
313 }
314
315 std::string_view AbcFile::GetNameWithoutHashtag(std::string_view full_name, std::string_view record_name) const
316 {
317 size_t pos = full_name.find(record_name);
318 std::string_view name = pos == std::string::npos ? full_name : full_name.substr(pos + record_name.length());
319 if (name[0] == '#') {
320 size_t sec_hashtag_idx = name.find_first_of('#', 1);
321 if (sec_hashtag_idx != std::string::npos && (sec_hashtag_idx + 1) <= name.size()) {
322 return name.substr(sec_hashtag_idx + 1);
323 }
324 }
325 return name;
326 }
327
328 std::string AbcFile::GetStringByInst(const Inst &inst) const
329 {
330 auto type = inst.GetType();
331 switch (type) {
332 case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
333 case InstType::DEFINEFUNC_IMM16_ID16_IMM8:
334 case InstType::DEFINEMETHOD_IMM8_ID16_IMM8:
335 case InstType::DEFINEMETHOD_IMM16_ID16_IMM8:
336 case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
337 case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
338 case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
339 uint32_t method_id = inst.GetImms()[1];
340 return GetStringByMethodId(EntityId(method_id));
341 }
342 case InstType::TRYLDGLOBALBYNAME_IMM8_ID16:
343 case InstType::TRYSTGLOBALBYNAME_IMM8_ID16:
344 case InstType::TRYLDGLOBALBYNAME_IMM16_ID16:
345 case InstType::TRYSTGLOBALBYNAME_IMM16_ID16:
346 case InstType::STCONSTTOGLOBALRECORD_IMM16_ID16:
347 case InstType::STTOGLOBALRECORD_IMM16_ID16:
348 case InstType::LDGLOBALVAR_IMM16_ID16:
349 case InstType::STGLOBALVAR_IMM16_ID16:
350 case InstType::LDOBJBYNAME_IMM8_ID16:
351 case InstType::LDOBJBYNAME_IMM16_ID16:
352 case InstType::STOBJBYNAME_IMM8_ID16_V8:
353 case InstType::STOBJBYNAME_IMM16_ID16_V8:
354 case InstType::LDSUPERBYNAME_IMM8_ID16:
355 case InstType::LDSUPERBYNAME_IMM16_ID16:
356 case InstType::STSUPERBYNAME_IMM8_ID16_V8:
357 case InstType::STSUPERBYNAME_IMM16_ID16_V8:
358 case InstType::LDTHISBYNAME_IMM8_ID16:
359 case InstType::LDTHISBYNAME_IMM16_ID16:
360 case InstType::STTHISBYNAME_IMM8_ID16:
361 case InstType::STTHISBYNAME_IMM16_ID16:
362 case InstType::STOWNBYNAME_IMM8_ID16_V8:
363 case InstType::STOWNBYNAME_IMM16_ID16_V8:
364 case InstType::STOWNBYNAMEWITHNAMESET_IMM8_ID16_V8:
365 case InstType::STOWNBYNAMEWITHNAMESET_IMM16_ID16_V8: {
366 uint32_t string_id = inst.GetImms()[1];
367 return GetStringByStringId(EntityId(string_id));
368 }
369 default:
370 return EMPTY_STR;
371 }
372 }
373
374 // TODO(wangyantian): may match multiple stlex inst when considering control flow
375 std::optional<FuncInstPair> AbcFile::GetStLexInstByLdLexInst(FuncInstPair func_inst_pair) const
376 {
377 Function *func = func_inst_pair.first;
378 const Inst &ld_lex_inst = func_inst_pair.second;
379 if (func == nullptr || !ld_lex_inst.IsInstLdLexVar()) {
380 return std::nullopt;
381 }
382
383 auto ld_imms = ld_lex_inst.GetImms();
384 uint32_t ld_level = ld_imms[0];
385 uint32_t ld_slot_id = ld_imms[1];
386 Function *cur_func = func;
387 uint32_t i = 0;
388 while (true) {
389 bool has_new_lexenv = false;
390 const auto &graph = cur_func->GetGraph();
391 // TODO: Multiple newlexenv instructions and poplexenv instruction are not correctly supported in
392 // the following code. Future fixes are required.
393 graph.VisitAllInstructions([&has_new_lexenv](const Inst &inst) {
394 if (inst.GetType() == InstType::NEWLEXENV_IMM8 || inst.GetType() == InstType::WIDE_NEWLEXENV_PREF_IMM16) {
395 has_new_lexenv = true;
396 }
397 });
398 if (has_new_lexenv) {
399 i++;
400 }
401 if (i == ld_level + 1) {
402 break;
403 }
404 cur_func = cur_func->GetParentFunction();
405 if (cur_func == nullptr) {
406 return std::nullopt;
407 }
408 }
409 auto &graph = cur_func->GetGraph();
410 Inst st_lex_inst = ld_lex_inst;
411 bool is_same_func = (cur_func == func_inst_pair.first);
412 graph.VisitAllInstructions([is_same_func, ld_lex_inst, ld_slot_id, &st_lex_inst](const Inst &inst) {
413 if (inst.IsInstStLexVar()) {
414 auto st_imms = inst.GetImms();
415 uint32_t st_level = st_imms[0];
416 uint32_t st_slot_id = st_imms[1];
417 if (st_level == 0 && st_slot_id == ld_slot_id) {
418 // Best effort to avoid the case where ld_lex_inst is some input of st_lex_inst
419 // Current heuristics for choosing a valid st_lex_inst (or relationship between conditions):
420 // 1. If no valid st_lex_inst is found (which is necessary to make the search process more sound).
421 // 2. If they are not in the same function.
422 // 3. If they are in the same function, but current st_lex_inst appears before ld_lex_inst (by PC).
423 // More advanced heuristics (e.g. preforming dfs on all inputs of st_lex_inst) should be considered.
424 if (st_lex_inst == ld_lex_inst || !is_same_func || inst.GetPc() < ld_lex_inst.GetPc()) {
425 st_lex_inst = inst;
426 }
427 }
428 }
429 });
430 if (st_lex_inst != ld_lex_inst) {
431 return FuncInstPair(cur_func, st_lex_inst);
432 }
433
434 return std::nullopt;
435 }
436
437 std::optional<FuncInstPair> AbcFile::GetStGlobalInstByLdGlobalInst(FuncInstPair func_inst_pair) const
438 {
439 const Function *func = func_inst_pair.first;
440 const Inst &ld_global_inst = func_inst_pair.second;
441 if (func == nullptr || !ld_global_inst.IsInstLdGlobal()) {
442 return std::nullopt;
443 }
444
445 uint32_t ld_str_id = ld_global_inst.GetImms()[0];
446 std::string record_name = func->GetRecordName();
447 Function *func_main;
448 // TODO(wangyantian): only consider that func_main_0 has StGlobal inst for now, what about other cases?
449 if (IsMergeAbc()) {
450 ASSERT(merge_def_func_map_.find(record_name) != merge_def_func_map_.end());
451 func_main = merge_def_func_map_.find(record_name)->second[0].get();
452 } else {
453 func_main = def_func_list_[0].get();
454 }
455 auto &graph = func_main->GetGraph();
456 Inst st_global_inst = ld_global_inst;
457 graph.VisitAllInstructions([ld_str_id, &st_global_inst](const Inst &inst) {
458 if (inst.IsInstStGlobal()) {
459 uint32_t st_str_id = inst.GetImms()[0];
460 if (st_str_id == ld_str_id) {
461 st_global_inst = inst;
462 }
463 }
464 });
465 if (st_global_inst != ld_global_inst) {
466 return FuncInstPair(func_main, st_global_inst);
467 }
468
469 return std::nullopt;
470 }
471
472 void AbcFile::ExtractDebugInfo()
473 {
474 debug_info_ = std::make_unique<const panda_file::DebugInfoExtractor>(panda_file_.get());
475 if (debug_info_ == nullptr) {
476 LOG(FATAL, DEFECT_SCAN_AUX) << "Failed to extract debug info";
477 }
478 }
479
480 void AbcFile::ExtractModuleInfo()
481 {
482 int module_offset = -1;
483 is_merge_abc_ = true;
484 for (uint32_t id : panda_file_->GetClasses()) {
485 EntityId class_id(id);
486 if (panda_file_->IsExternal(class_id)) {
487 continue;
488 }
489 panda_file::ClassDataAccessor cda(*panda_file_, class_id);
490 const char *desc = utf::Mutf8AsCString(cda.GetDescriptor());
491 if (std::strcmp(MODULE_CLASS, desc) == 0) {
492 is_merge_abc_ = false;
493 cda.EnumerateFields([&](panda_file::FieldDataAccessor &field_accessor) -> void {
494 EntityId field_name_id = field_accessor.GetNameId();
495 StringData sd = panda_file_->GetStringData(field_name_id);
496 if (std::strcmp(utf::Mutf8AsCString(sd.data), filename_.data())) {
497 module_offset = field_accessor.GetValue<int32_t>().value();
498 return;
499 }
500 });
501 break;
502 }
503 }
504 if (is_merge_abc_) {
505 ExtractMergeAbcModuleInfo();
506 return;
507 } else if (module_offset == -1) {
508 return;
509 }
510
511 std::unique_ptr<ModuleRecord> module_record = std::make_unique<ModuleRecord>(filename_);
512 if (module_record == nullptr) {
513 LOG(FATAL, DEFECT_SCAN_AUX) << "Can not create ModuleRecord instance for '" << filename_ << "'";
514 }
515 ExtractModuleRecord(EntityId(module_offset), module_record);
516 AddModuleRecord(MODULE_CLASS, std::move(module_record));
517 }
518
519 void AbcFile::ExtractMergeAbcModuleInfo()
520 {
521 for (uint32_t id : panda_file_->GetClasses()) {
522 EntityId class_id(id);
523 if (panda_file_->IsExternal(class_id)) {
524 continue;
525 }
526 panda_file::ClassDataAccessor cda(*panda_file_, class_id);
527 const char *desc = utf::Mutf8AsCString(cda.GetDescriptor());
528 cda.EnumerateFields([&](panda_file::FieldDataAccessor &field_accessor) -> void {
529 EntityId field_name_id = field_accessor.GetNameId();
530 StringData sd = panda_file_->GetStringData(field_name_id);
531 if (std::strcmp(utf::Mutf8AsCString(sd.data), MODULE_IDX_FIELD_NAME) != 0) {
532 return;
533 }
534 auto module_offset = field_accessor.GetValue<int32_t>().value();
535 std::unique_ptr<ModuleRecord> module_record = std::make_unique<ModuleRecord>(desc);
536 ASSERT(module_record != nullptr);
537 ExtractModuleRecord(EntityId(module_offset), module_record);
538 AddModuleRecord(std::string(desc), std::move(module_record));
539 });
540 }
541 }
542
543 void AbcFile::ExtractModuleRecord(EntityId module_id, std::unique_ptr<ModuleRecord> &module_record)
544 {
545 ModuleDataAccessor mda(*panda_file_, module_id);
546 const std::vector<uint32_t> &request_modules_idx = mda.getRequestModules();
547 std::vector<std::string> request_modules;
548 for (size_t idx = 0; idx < request_modules_idx.size(); ++idx) {
549 request_modules.push_back(GetStringByStringId(EntityId(request_modules_idx[idx])));
550 }
551 module_record->SetRequestModules(request_modules);
552
553 size_t regular_import_num = 0;
554 size_t local_export_num = 0;
555 mda.EnumerateModuleRecord([&](const ModuleTag &tag, uint32_t export_name_offset, uint32_t module_request_idx,
556 uint32_t import_name_offset, uint32_t local_name_offset) {
557 size_t request_num = request_modules.size();
558 ASSERT(request_num == 0 || module_request_idx < request_num);
559 std::string module_request = EMPTY_STR;
560 if (request_num != 0) {
561 module_request = request_modules[module_request_idx];
562 }
563 switch (tag) {
564 case ModuleTag::REGULAR_IMPORT: {
565 ++regular_import_num;
566 std::string local_name = GetStringByStringId(EntityId(local_name_offset));
567 std::string import_name = GetStringByStringId(EntityId(import_name_offset));
568 module_record->AddImportEntry({module_request, import_name, local_name});
569 LOG(DEBUG, DEFECT_SCAN_AUX) << "ModuleRecord adds a regular import: [" << module_request << ", "
570 << import_name << ", " << local_name << "]";
571 break;
572 }
573 case ModuleTag::NAMESPACE_IMPORT: {
574 std::string local_name = GetStringByStringId(EntityId(local_name_offset));
575 module_record->AddImportEntry({module_request, "*", local_name});
576 LOG(DEBUG, DEFECT_SCAN_AUX)
577 << "ModuleRecord adds a namespace import: [" << module_request << ", *, " << local_name << "]";
578 break;
579 }
580 case ModuleTag::LOCAL_EXPORT: {
581 ++local_export_num;
582 std::string local_name = GetStringByStringId(EntityId(local_name_offset));
583 std::string export_name = GetStringByStringId(EntityId(export_name_offset));
584 module_record->AddExportEntry({export_name, EMPTY_STR, EMPTY_STR, local_name});
585 LOG(DEBUG, DEFECT_SCAN_AUX)
586 << "ModuleRecord adds a local export: [" << export_name << ", null, null, " << local_name << "]";
587 break;
588 }
589 case ModuleTag::INDIRECT_EXPORT: {
590 std::string export_name = GetStringByStringId(EntityId(export_name_offset));
591 std::string import_name = GetStringByStringId(EntityId(import_name_offset));
592 module_record->AddExportEntry({export_name, module_request, import_name, EMPTY_STR});
593 LOG(DEBUG, DEFECT_SCAN_AUX) << "ModuleRecord adds an indirect export: [" << export_name << ", "
594 << module_request << ", " << import_name << ", null]";
595 break;
596 }
597 case ModuleTag::STAR_EXPORT: {
598 module_record->AddExportEntry({EMPTY_STR, module_request, "*", EMPTY_STR});
599 LOG(DEBUG, DEFECT_SCAN_AUX) << "ModuleRecord adds a start export: ["
600 << "null, " << module_request << "*, null]";
601 break;
602 }
603 default: {
604 UNREACHABLE();
605 break;
606 }
607 }
608 });
609 module_record->SetRegularImportNum(regular_import_num);
610 module_record->SetLocalExportNum(local_export_num);
611 }
612
613 void AbcFile::AddModuleRecord(std::string record_name, std::unique_ptr<ModuleRecord> &&module_record)
614 {
615 ASSERT(module_record_map_.find(record_name) == module_record_map_.end());
616 module_record_map_[record_name] = module_record.get();
617 module_record_list_.emplace_back(std::move(module_record));
618 }
619
620 void AbcFile::InitializeAllDefinedFunction()
621 {
622 for (uint32_t id : panda_file_->GetClasses()) {
623 EntityId class_id {id};
624 if (panda_file_->IsExternal(class_id)) {
625 continue;
626 }
627
628 panda_file::ClassDataAccessor cda {*panda_file_, class_id};
629 cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) {
630 if (!mda.IsExternal()) {
631 std::string func_name = GetStringByStringId(mda.GetNameId());
632 std::string record_name = "";
633 std::string name = func_name;
634 if (IsMergeAbc()) {
635 record_name = std::string(utf::Mutf8AsCString(cda.GetName().data));
636 record_name_set_.insert(record_name);
637 func_name = record_name + func_name;
638 }
639 EntityId m_id = mda.GetMethodId();
640 panda_file::CodeDataAccessor cda {*panda_file_, mda.GetCodeId().value()};
641 uint32_t arg_count = cda.GetNumArgs();
642 compiler::Graph *graph = GenerateFunctionGraph(mda, func_name);
643 if (graph == nullptr) {
644 return;
645 }
646 std::unique_ptr<Function> func =
647 std::make_unique<Function>(record_name, func_name, m_id, arg_count, Graph(graph), this);
648 if (func == nullptr) {
649 LOG(FATAL, DEFECT_SCAN_AUX) << "Can not allocate memory when processing '" << filename_ << "'";
650 }
651 LOG(DEBUG, DEFECT_SCAN_AUX) << "Create a new function: " << func_name;
652 if (IsMergeAbc()) {
653 AddMergedDefinedFunction(std::move(func));
654 } else {
655 AddDefinedFunction(std::move(func));
656 }
657 }
658 });
659 }
660 }
661
662 void AbcFile::ExtractDefinedClassAndFunctionInfo()
663 {
664 if (IsMergeAbc()) {
665 ExtractMergedDefinedClassAndFunctionInfo();
666 } else {
667 ExtractSingleDefinedClassAndFunctionInfo();
668 }
669 }
670
671 void AbcFile::ExtractMergedDefinedClassAndFunctionInfo()
672 {
673 for (auto &merge_def_func_pair : merge_def_func_map_) {
674 for (auto &func : merge_def_func_pair.second) {
675 ExtractMergedClassAndFunctionInfo(func.get());
676 }
677 }
678 std::unordered_set<const Function *> processed_func;
679 for (auto &merge_def_class_pair : merge_def_class_map_) {
680 for (auto &def_class : merge_def_class_pair.second) {
681 Function *def_func = def_class->GetDefiningFunction();
682 if (def_func != nullptr && processed_func.count(def_func) == 0) {
683 ExtractClassInheritInfo(def_func);
684 processed_func.insert(def_func);
685 }
686 }
687 }
688 for (auto &merge_def_func_pair : merge_def_func_map_) {
689 for (auto &func : merge_def_func_pair.second) {
690 ExtractFunctionCalleeInfo(func.get());
691 }
692 }
693 }
694
695 void AbcFile::ExtractSingleDefinedClassAndFunctionInfo()
696 {
697 for (auto &func : def_func_list_) {
698 ExtractClassAndFunctionInfo(func.get());
699 }
700
701 std::unordered_set<const Function *> processed_func;
702 for (auto &def_class : def_class_list_) {
703 Function *def_func = def_class->GetDefiningFunction();
704 if (def_func != nullptr && processed_func.count(def_func) == 0) {
705 ExtractClassInheritInfo(def_func);
706 processed_func.insert(def_func);
707 }
708 }
709
710 for (auto &func : def_func_list_) {
711 ExtractFunctionCalleeInfo(func.get());
712 }
713 }
714
715 void AbcFile::ExtractClassAndFunctionInfo(Function *func)
716 {
717 auto &graph = func->GetGraph();
718 graph.VisitAllInstructions([&](const Inst &inst) {
719 auto type = inst.GetType();
720 switch (type) {
721 case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
722 case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
723 case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
724 auto def_class = ResolveDefineClassWithBufferInst(func, inst);
725 AddDefinedClass(std::move(def_class));
726 break;
727 }
728 case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
729 case InstType::DEFINEFUNC_IMM16_ID16_IMM8: {
730 Function *def_func = ResolveDefineFuncInstCommon(func, inst);
731 BuildFunctionDefineChain(func, def_func);
732 break;
733 }
734 case InstType::DEFINEMETHOD_IMM8_ID16_IMM8:
735 case InstType::DEFINEMETHOD_IMM16_ID16_IMM8: {
736 auto member_func = ResolveDefineFuncInstCommon(func, inst);
737 BuildFunctionDefineChain(func, member_func);
738 // resolve the class where it's defined
739 ResolveDefineMethodInst(member_func, inst);
740 break;
741 }
742 case InstType::CALLRUNTIME_CREATEPRIVATEPROPERTY_PREF_IMM16_ID16: {
743 ResolveDefineMethodWithBufferInst(func, inst);
744 break;
745 }
746 default:
747 break;
748 }
749 });
750 }
751
752 void AbcFile::ExtractMergedClassAndFunctionInfo(Function *func)
753 {
754 auto &graph = func->GetGraph();
755 std::string record_name = func->GetRecordName();
756 graph.VisitAllInstructions([&](const Inst &inst) {
757 auto type = inst.GetType();
758 switch (type) {
759 case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
760 case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
761 case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
762 auto def_class = ResolveDefineClassWithBufferInst(func, inst);
763 AddMergedDefinedClass(std::move(def_class), record_name);
764 break;
765 }
766 case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
767 case InstType::DEFINEFUNC_IMM16_ID16_IMM8: {
768 Function *def_func = ResolveDefineFuncInstCommon(func, inst);
769 BuildFunctionDefineChain(func, def_func);
770 break;
771 }
772 case InstType::DEFINEMETHOD_IMM8_ID16_IMM8:
773 case InstType::DEFINEMETHOD_IMM16_ID16_IMM8: {
774 auto member_func = ResolveDefineFuncInstCommon(func, inst);
775 BuildFunctionDefineChain(func, member_func);
776 // resolve the class where it's defined
777 ResolveDefineMethodInst(member_func, inst);
778 break;
779 }
780 case InstType::CALLRUNTIME_CREATEPRIVATEPROPERTY_PREF_IMM16_ID16: {
781 ResolveDefineMethodWithBufferInst(func, inst);
782 break;
783 }
784 default:
785 break;
786 }
787 });
788 }
789
790 void AbcFile::ExtractClassInheritInfo(Function *func) const
791 {
792 auto &graph = func->GetGraph();
793 std::string record_name = func->GetRecordName();
794 graph.VisitAllInstructions([&](const Inst &inst) {
795 if (inst.GetType() != InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8 &&
796 inst.GetType() != InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8 &&
797 inst.GetType() != InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8) {
798 return;
799 }
800
801 Class *cur_class = GetClassByNameImpl(record_name + GetStringByInst(inst));
802 ASSERT(cur_class != nullptr);
803 Inst def_class_input1 = inst.GetInputInsts()[0];
804 auto [ret_ptr, ret_sym, ret_type] = ResolveInstCommon(func, def_class_input1);
805 if (ret_ptr != nullptr && ret_type == ResolveType::CLASS_OBJECT) {
806 auto par_class = reinterpret_cast<const Class *>(ret_ptr);
807 cur_class->SetParentClass(par_class);
808 return;
809 }
810 size_t first_delim_idx = ret_sym.find_first_of(DELIM);
811 size_t last_delim_idx = ret_sym.find_last_of(DELIM);
812 std::string par_class_name = ret_sym;
813 std::string var_name = EMPTY_STR;
814 if (last_delim_idx != std::string::npos) {
815 par_class_name = ret_sym.substr(last_delim_idx + 1);
816 var_name = ret_sym.substr(0, first_delim_idx);
817 cur_class->SetParentClassName(record_name + par_class_name);
818 }
819 std::string record_name = func->GetRecordName();
820 if (ret_type == ResolveType::UNRESOLVED_MODULE) {
821 std::string imp_par_class_name = GetImportNameByLocalName(par_class_name, record_name);
822 if (!imp_par_class_name.empty()) {
823 cur_class->SetParentClassName(record_name + imp_par_class_name);
824 }
825 std::string inter_name = var_name.empty() ? par_class_name : var_name;
826 std::string module_name = GetModuleNameByLocalName(inter_name, record_name);
827 if (!module_name.empty()) {
828 cur_class->SetParClassExternalModuleName(module_name);
829 }
830 }
831 if (ret_type == ResolveType::UNRESOLVED_GLOBAL_VAR) {
832 cur_class->SetParentClassName(record_name + par_class_name);
833 var_name = var_name.empty() ? var_name : ret_sym.substr(0, last_delim_idx);
834 cur_class->SetParClassGlobalVarName(var_name);
835 }
836 });
837 }
838
839 void AbcFile::ExtractFunctionCalleeInfo(Function *func)
840 {
841 auto &graph = func->GetGraph();
842 graph.VisitAllInstructions([&](const Inst &inst) {
843 std::unique_ptr<CalleeInfo> callee_info {nullptr};
844 switch (inst.GetType()) {
845 case InstType::CALLARG0_IMM8: {
846 callee_info = ResolveCallInstCommon(func, inst);
847 callee_info->SetCalleeArgCount(0);
848 break;
849 }
850 case InstType::CALLARG1_IMM8_V8: {
851 callee_info = ResolveCallInstCommon(func, inst, 1);
852 callee_info->SetCalleeArgCount(1);
853 break;
854 }
855 case InstType::CALLARGS2_IMM8_V8_V8: {
856 constexpr int ARG_COUNT = 2;
857 callee_info = ResolveCallInstCommon(func, inst, ARG_COUNT);
858 callee_info->SetCalleeArgCount(ARG_COUNT);
859 break;
860 }
861 case InstType::CALLARGS3_IMM8_V8_V8_V8: {
862 constexpr int ARG_COUNT = 3;
863 callee_info = ResolveCallInstCommon(func, inst, ARG_COUNT);
864 callee_info->SetCalleeArgCount(ARG_COUNT);
865 break;
866 }
867 case InstType::CALLRANGE_IMM8_IMM8_V8: {
868 uint32_t arg_count = inst.GetImms()[1];
869 callee_info = ResolveCallInstCommon(func, inst, arg_count);
870 callee_info->SetCalleeArgCount(arg_count);
871 break;
872 }
873 case InstType::WIDE_CALLRANGE_PREF_IMM16_V8: {
874 uint32_t arg_count = inst.GetImms()[0];
875 callee_info = ResolveCallInstCommon(func, inst, arg_count);
876 callee_info->SetCalleeArgCount(arg_count);
877 break;
878 }
879 case InstType::SUPERCALLSPREAD_IMM8_V8: {
880 callee_info = ResolveCallInstCommon(func, inst, 1);
881 break;
882 }
883 case InstType::APPLY_IMM8_V8_V8: {
884 constexpr uint32_t FUNC_OBJ_INDEX = 2;
885 callee_info = ResolveCallInstCommon(func, inst, FUNC_OBJ_INDEX);
886 break;
887 }
888 case InstType::CALLTHIS0_IMM8_V8: {
889 callee_info = ResolveCallInstCommon(func, inst, 1);
890 callee_info->SetCalleeArgCount(0);
891 break;
892 }
893 case InstType::CALLTHIS1_IMM8_V8_V8: {
894 constexpr int ARG_COUNT = 1;
895 // 1 represents the this pointer
896 callee_info = ResolveCallInstCommon(func, inst, ARG_COUNT + 1);
897 callee_info->SetCalleeArgCount(ARG_COUNT);
898 break;
899 }
900 case InstType::CALLTHIS2_IMM8_V8_V8_V8: {
901 constexpr int ARG_COUNT = 2;
902 callee_info = ResolveCallInstCommon(func, inst, ARG_COUNT + 1);
903 callee_info->SetCalleeArgCount(ARG_COUNT);
904 break;
905 }
906 case InstType::CALLTHIS3_IMM8_V8_V8_V8_V8: {
907 constexpr int ARG_COUNT = 3;
908 callee_info = ResolveCallInstCommon(func, inst, ARG_COUNT + 1);
909 callee_info->SetCalleeArgCount(ARG_COUNT);
910 break;
911 }
912 case InstType::CALLTHISRANGE_IMM8_IMM8_V8: {
913 uint32_t arg_count = inst.GetImms()[1];
914 callee_info = ResolveCallInstCommon(func, inst, arg_count + 1);
915 callee_info->SetCalleeArgCount(arg_count);
916 break;
917 }
918 case InstType::WIDE_CALLTHISRANGE_PREF_IMM16_V8: {
919 uint32_t arg_count = inst.GetImms()[0];
920 callee_info = ResolveCallInstCommon(func, inst, arg_count + 1);
921 callee_info->SetCalleeArgCount(arg_count);
922 break;
923 }
924 case InstType::SUPERCALLTHISRANGE_IMM8_IMM8_V8:
925 case InstType::SUPERCALLARROWRANGE_IMM8_IMM8_V8: {
926 uint32_t arg_count = inst.GetImms()[1];
927 callee_info = ResolveSuperCallInst(func, inst);
928 callee_info->SetCalleeArgCount(arg_count);
929 break;
930 }
931 case InstType::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8:
932 case InstType::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8: {
933 uint32_t arg_count = inst.GetImms()[0];
934 callee_info = ResolveSuperCallInst(func, inst);
935 callee_info->SetCalleeArgCount(arg_count);
936 break;
937 }
938 default:
939 break;
940 }
941 if (callee_info != nullptr) {
942 AddCalleeInfo(std::move(callee_info));
943 }
944 });
945 }
946
947 void AbcFile::BuildFunctionDefineChain(Function *parent_func, Function *child_func) const
948 {
949 if (parent_func == nullptr || child_func == nullptr || child_func->GetParentFunction() == parent_func) {
950 return;
951 }
952 child_func->SetParentFunction(parent_func);
953 parent_func->AddDefinedFunction(child_func);
954 }
955
956 void AbcFile::BuildClassAndMemberFuncRelation(Class *clazz, Function *member_func) const
957 {
958 if (clazz == nullptr || member_func == nullptr || member_func->GetClass() == clazz) {
959 return;
960 }
961 clazz->AddMemberFunction(member_func);
962 member_func->SetClass(clazz);
963 }
964
965 void AbcFile::ExtractClassAndFunctionExportList()
966 {
967 if (IsMergeAbc()) {
968 ExtractMergedClassAndFunctionExportList();
969 } else {
970 ExtractSingleClassAndFunctionExportList();
971 }
972 }
973
974 void AbcFile::ExtractMergedClassAndFunctionExportList()
975 {
976 if (merge_def_func_map_.empty()) {
977 return;
978 }
979
980 for (auto &merge_def_func_pair : merge_def_func_map_) {
981 if (merge_def_func_pair.second.empty()) {
982 continue;
983 }
984 const Function *func_main = merge_def_func_pair.second[0].get();
985 auto &graph = func_main->GetGraph();
986 graph.VisitAllInstructions([&](const Inst &inst) {
987 auto type = inst.GetType();
988 if (type == InstType::STMODULEVAR_IMM8 || type == InstType::WIDE_STMODULEVAR_PREF_IMM16) {
989 AddExportListForMerge(func_main, inst);
990 }
991 });
992 }
993 }
994
995 void AbcFile::AddExportListForMerge(const Function *func_main, const Inst &inst)
996 {
997 [[maybe_unused]] auto type = inst.GetType();
998 ASSERT(type == InstType::STMODULEVAR_IMM8 || type == InstType::WIDE_STMODULEVAR_PREF_IMM16);
999
1000 std::string record_name = func_main->GetRecordName();
1001 Inst st_module_input0 = inst.GetInputInsts()[0];
1002 switch (st_module_input0.GetType()) {
1003 case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
1004 case InstType::DEFINEFUNC_IMM16_ID16_IMM8: {
1005 auto export_func = ResolveDefineFuncInstCommon(func_main, st_module_input0);
1006 ASSERT(export_func != nullptr);
1007 if (merge_export_func_map_.find(record_name) == merge_export_func_map_.end()) {
1008 merge_export_func_map_.emplace(record_name, std::vector<const Function *>());
1009 }
1010 merge_export_func_map_[record_name].push_back(export_func);
1011 break;
1012 }
1013 case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
1014 case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
1015 case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
1016 Class *export_clazz = GetClassByNameImpl(record_name + GetStringByInst(st_module_input0));
1017 ASSERT(export_clazz != nullptr);
1018 if (merge_export_class_map_.find(record_name) == merge_export_class_map_.end()) {
1019 merge_export_class_map_.emplace(record_name, std::vector<const Class *>());
1020 }
1021 merge_export_class_map_[record_name].push_back(export_clazz);
1022 break;
1023 }
1024 default:
1025 break;
1026 }
1027 }
1028
1029 void AbcFile::ExtractSingleClassAndFunctionExportList()
1030 {
1031 if (!IsModule() || def_func_list_.empty()) {
1032 return;
1033 }
1034 const Function *func_main = def_func_list_[0].get();
1035 ASSERT(func_main->GetFunctionName() == ENTRY_FUNCTION_NAME);
1036 auto &graph = func_main->GetGraph();
1037 std::string record_name = func_main->GetRecordName();
1038 graph.VisitAllInstructions([&](const Inst &inst) {
1039 auto type = inst.GetType();
1040 if (type == InstType::STMODULEVAR_IMM8 || type == InstType::WIDE_STMODULEVAR_PREF_IMM16) {
1041 AddExportListForSingle(func_main, inst);
1042 }
1043 });
1044 }
1045
1046 void AbcFile::AddExportListForSingle(const Function *func_main, const Inst &inst)
1047 {
1048 [[maybe_unused]] auto type = inst.GetType();
1049 ASSERT(type == InstType::STMODULEVAR_IMM8 || type == InstType::WIDE_STMODULEVAR_PREF_IMM16);
1050 Inst st_module_input0 = inst.GetInputInsts()[0];
1051 switch (st_module_input0.GetType()) {
1052 case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
1053 case InstType::DEFINEFUNC_IMM16_ID16_IMM8: {
1054 auto export_func = ResolveDefineFuncInstCommon(func_main, st_module_input0);
1055 ASSERT(export_func != nullptr);
1056 export_func_list_.push_back(export_func);
1057 break;
1058 }
1059 case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
1060 case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
1061 case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
1062 Class *export_clazz = GetClassByNameImpl(GetStringByInst(st_module_input0));
1063 ASSERT(export_clazz != nullptr);
1064 export_class_list_.push_back(export_clazz);
1065 break;
1066 }
1067 default:
1068 break;
1069 }
1070 }
1071
1072 compiler::Graph *AbcFile::GenerateFunctionGraph(const panda_file::MethodDataAccessor &mda, std::string_view func_name)
1073 {
1074 panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
1075 auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(mda.GetMethodId().GetOffset());
1076 compiler::options.SetCompilerUseSafepoint(false);
1077 compiler::options.SetCompilerMaxBytecodeSize(bytecodeopt::MAX_BYTECODE_SIZE);
1078 compiler::Graph *graph = allocator_->New<compiler::Graph>(allocator_.get(), local_allocator_.get(), Arch::NONE,
1079 method_ptr, &adapter, false, nullptr, true, true);
1080 if ((graph == nullptr) || !graph->RunPass<compiler::IrBuilder>()) {
1081 LOG(FATAL, DEFECT_SCAN_AUX) << "Cannot generate graph for function '" << func_name << "'";
1082 }
1083 return graph;
1084 }
1085
1086 ResolveResult AbcFile::ResolveInstCommon(Function *func, Inst inst) const
1087 {
1088 auto type = inst.GetType();
1089 std::string record_name = func->GetRecordName();
1090 switch (type) {
1091 case InstType::DEFINEFUNC_IMM8_ID16_IMM8:
1092 case InstType::DEFINEFUNC_IMM16_ID16_IMM8: {
1093 std::string func_name = record_name + GetStringByInst(inst);
1094 const Function *func = GetFunctionByName(func_name);
1095 ASSERT(func != nullptr);
1096 return std::make_tuple(func, EMPTY_STR, ResolveType::FUNCTION_OBJECT);
1097 }
1098 case InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8:
1099 case InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8:
1100 case InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8: {
1101 std::string class_name = record_name + GetStringByInst(inst);
1102 const Class *clazz = GetClassByName(class_name);
1103 ASSERT(clazz != nullptr);
1104 return std::make_tuple(clazz, EMPTY_STR, ResolveType::CLASS_OBJECT);
1105 }
1106 case InstType::NEWOBJAPPLY_IMM8_V8:
1107 case InstType::NEWOBJAPPLY_IMM16_V8:
1108 case InstType::NEWOBJRANGE_IMM8_IMM8_V8:
1109 case InstType::NEWOBJRANGE_IMM16_IMM8_V8:
1110 case InstType::WIDE_NEWOBJRANGE_PREF_IMM16_V8: {
1111 Inst newobj_input0 = inst.GetInputInsts()[0];
1112 auto resolve_res = ResolveInstCommon(func, newobj_input0);
1113 return HandleNewObjInstResolveResultCommon(resolve_res);
1114 }
1115 case InstType::LDOBJBYNAME_IMM8_ID16:
1116 case InstType::LDOBJBYNAME_IMM16_ID16: {
1117 Inst ld_obj_input0 = inst.GetInputInsts()[0];
1118 auto resolve_res = ResolveInstCommon(func, ld_obj_input0);
1119 return HandleLdObjByNameInstResolveResult(inst, resolve_res, record_name);
1120 }
1121 case InstType::LDLEXVAR_IMM4_IMM4:
1122 case InstType::LDLEXVAR_IMM8_IMM8:
1123 case InstType::WIDE_LDLEXVAR_PREF_IMM16_IMM16: {
1124 auto p = GetStLexInstByLdLexInst({func, inst});
1125 if (p == std::nullopt) {
1126 return std::make_tuple(nullptr, EMPTY_STR, ResolveType::UNRESOLVED_OTHER);
1127 }
1128 return ResolveInstCommon(p.value().first, p.value().second);
1129 }
1130 case InstType::STLEXVAR_IMM4_IMM4:
1131 case InstType::STLEXVAR_IMM8_IMM8:
1132 case InstType::WIDE_STLEXVAR_PREF_IMM16_IMM16: {
1133 Inst stlex_input0 = inst.GetInputInsts()[0];
1134 return ResolveInstCommon(func, stlex_input0);
1135 }
1136 case InstType::LDLOCALMODULEVAR_IMM8:
1137 case InstType::WIDE_LDLOCALMODULEVAR_PREF_IMM16: {
1138 size_t index = inst.GetImms()[0];
1139 auto module_record = GetModuleRecordByName(record_name);
1140 const std::string &export_name = module_record->GetExportNameByIndex(index);
1141 const Function *func = GetExportFunctionByExportName(export_name, record_name);
1142 if (func != nullptr) {
1143 return std::make_tuple(func, EMPTY_STR, ResolveType::FUNCTION_OBJECT);
1144 }
1145 const Class *clazz = GetExportClassByExportName(export_name, record_name);
1146 if (clazz != nullptr) {
1147 return std::make_tuple(clazz, EMPTY_STR, ResolveType::CLASS_OBJECT);
1148 }
1149 return std::make_tuple(nullptr, EMPTY_STR, ResolveType::UNRESOLVED_OTHER);
1150 }
1151 case InstType::LDEXTERNALMODULEVAR_IMM8:
1152 case InstType::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16: {
1153 size_t index = inst.GetImms()[0];
1154 auto module_record = GetModuleRecordByName(func->GetRecordName());
1155 const std::string &inter_name = module_record->GetImportLocalNameByIndex(index);
1156 return std::make_tuple(nullptr, inter_name, ResolveType::UNRESOLVED_MODULE);
1157 }
1158 case InstType::GETMODULENAMESPACE_IMM8:
1159 case InstType::WIDE_GETMODULENAMESPACE_PREF_IMM16: {
1160 size_t index = inst.GetImms()[0];
1161 auto module_record = GetModuleRecordByName(func->GetRecordName());
1162 const std::string &str = module_record->GetImportNamespaceNameByIndex(index);
1163 return std::make_tuple(nullptr, str, ResolveType::UNRESOLVED_MODULE);
1164 }
1165 case InstType::LDGLOBAL: {
1166 // TODO(wangyantian): load a specific global variable, namely 'globalThis'
1167 return std::make_tuple(nullptr, EMPTY_STR, ResolveType::UNRESOLVED_OTHER);
1168 }
1169 case InstType::LDGLOBALVAR_IMM16_ID16:
1170 case InstType::TRYLDGLOBALBYNAME_IMM8_ID16:
1171 case InstType::TRYLDGLOBALBYNAME_IMM16_ID16: {
1172 std::string str = GetStringByInst(inst);
1173 auto p = GetStGlobalInstByLdGlobalInst({func, inst});
1174 if (p == std::nullopt) {
1175 return std::make_tuple(nullptr, str, ResolveType::UNRESOLVED_GLOBAL_VAR);
1176 }
1177 auto [ret_ptr, ret_sym, ret_type] = ResolveInstCommon(p.value().first, p.value().second);
1178 if (ret_ptr != nullptr) {
1179 return std::make_tuple(ret_ptr, str, ret_type);
1180 }
1181 return std::make_tuple(nullptr, str, ResolveType::UNRESOLVED_GLOBAL_VAR);
1182 }
1183 case InstType::TRYSTGLOBALBYNAME_IMM8_ID16:
1184 case InstType::TRYSTGLOBALBYNAME_IMM16_ID16:
1185 case InstType::STGLOBALVAR_IMM16_ID16:
1186 case InstType::STCONSTTOGLOBALRECORD_IMM16_ID16:
1187 case InstType::STTOGLOBALRECORD_IMM16_ID16: {
1188 Inst stglobal_input0 = inst.GetInputInsts()[0];
1189 return ResolveInstCommon(func, stglobal_input0);
1190 }
1191 case InstType::OPCODE_PHI: {
1192 // TODO: only the next unvisited path is considered for now, what about other paths?
1193 // TODO: when all inputs of the phi instruction contain a path to the phi instruction itself,
1194 // the current solution still causes infinite recursion and stack overflow. However, this case
1195 // should not occur in real-world applications. However, the following part needs to be redesigned
1196 // when encountering such scenarios.
1197 auto phi_input_idx = func->GetAndUpdateToVisitInputForInst(inst);
1198 return ResolveInstCommon(func, inst.GetInputInsts()[phi_input_idx]);
1199 }
1200 // don't deal with the situation that func obj comes from parameter or the output of another call inst
1201 default: {
1202 return std::make_tuple(nullptr, EMPTY_STR, ResolveType::UNRESOLVED_OTHER);
1203 }
1204 }
1205 }
1206
1207 ResolveResult AbcFile::HandleLdObjByNameInstResolveResult(const Inst &ldobjbyname_inst,
1208 const ResolveResult &resolve_res,
1209 const std::string record_name) const
1210 {
1211 auto &[ret_ptr, ret_sym, ret_type] = resolve_res;
1212 std::string name = GetStringByInst(ldobjbyname_inst);
1213 switch (ret_type) {
1214 case ResolveType::UNRESOLVED_MODULE:
1215 case ResolveType::UNRESOLVED_GLOBAL_VAR: {
1216 return std::make_tuple(nullptr, ret_sym + "." + name, ret_type);
1217 }
1218 case ResolveType::FUNCTION_OBJECT: {
1219 ASSERT(ret_ptr != nullptr);
1220 if (name == CALL || name == APPLY) {
1221 return std::make_tuple(ret_ptr, EMPTY_STR, ResolveType::FUNCTION_OBJECT);
1222 }
1223 return std::make_tuple(nullptr, ret_sym + "." + name, ResolveType::UNRESOLVED_OTHER);
1224 }
1225 case ResolveType::CLASS_OBJECT:
1226 case ResolveType::CLASS_INSTANCE: {
1227 ASSERT(ret_ptr != nullptr);
1228 // TODO(wangyantian): distinguish static func from member func in a class
1229 const void *member_func =
1230 reinterpret_cast<const Class *>(ret_ptr)->GetMemberFunctionByName(record_name + name);
1231 if (member_func != nullptr) {
1232 return std::make_tuple(member_func, name, ResolveType::FUNCTION_OBJECT);
1233 }
1234 return std::make_tuple(nullptr, ret_sym + "." + name, ResolveType::UNRESOLVED_OTHER);
1235 }
1236 default: {
1237 return std::make_tuple(nullptr, ret_sym + "." + name, ResolveType::UNRESOLVED_OTHER);
1238 }
1239 }
1240 }
1241
1242 ResolveResult AbcFile::HandleNewObjInstResolveResultCommon(const ResolveResult &resolve_res) const
1243 {
1244 auto &[ret_ptr, ret_sym, ret_type] = resolve_res;
1245 switch (ret_type) {
1246 case ResolveType::CLASS_OBJECT: {
1247 ASSERT(ret_ptr != nullptr);
1248 return std::make_tuple(ret_ptr, EMPTY_STR, ResolveType::CLASS_INSTANCE);
1249 }
1250 case ResolveType::UNRESOLVED_GLOBAL_VAR:
1251 case ResolveType::UNRESOLVED_MODULE: {
1252 return std::make_tuple(nullptr, ret_sym, ret_type);
1253 }
1254 default: {
1255 return std::make_tuple(nullptr, ret_sym, ResolveType::UNRESOLVED_OTHER);
1256 }
1257 }
1258 }
1259
1260 Function *AbcFile::ResolveDefineFuncInstCommon(const Function *func, const Inst &def_func_inst) const
1261 {
1262 std::string record_name = func->GetRecordName();
1263 std::string def_func_name = record_name + GetStringByInst(def_func_inst);
1264 Function *def_func = GetFunctionByNameImpl(def_func_name);
1265 ASSERT(def_func != nullptr);
1266 return def_func;
1267 }
1268
1269 std::unique_ptr<Class> AbcFile::ResolveDefineClassWithBufferInst(Function *func, const Inst &define_class_inst) const
1270 {
1271 auto imms = define_class_inst.GetImms();
1272 auto m_id = EntityId(imms[1]);
1273 std::string record_name = func->GetRecordName();
1274 std::string class_name = record_name + GetStringByMethodId(m_id);
1275 std::unique_ptr<Class> def_class = std::make_unique<Class>(class_name, record_name, this, func);
1276 if (def_class == nullptr) {
1277 LOG(FATAL, DEFECT_SCAN_AUX) << "Can not allocate memory when processing '" << filename_ << "'";
1278 }
1279 LOG(DEBUG, DEFECT_SCAN_AUX) << "Create a new class: " << class_name;
1280 func->AddDefinedClass(def_class.get());
1281
1282 // handle ctor of the class
1283 std::string ctor_name = record_name + GetStringByInst(define_class_inst);
1284 HandleMemberFunctionFromClassBuf(ctor_name, func, def_class.get());
1285
1286 auto literal_array_id = EntityId(imms[2]);
1287 panda_file::LiteralDataAccessor lit_array_accessor(*panda_file_, panda_file_->GetLiteralArraysId());
1288 lit_array_accessor.EnumerateLiteralVals(
1289 literal_array_id, [&](const panda_file::LiteralDataAccessor::LiteralValue &value, const LiteralTag &tag) {
1290 if (tag == LiteralTag::METHOD || tag == panda_file::LiteralTag::GETTER ||
1291 tag == panda_file::LiteralTag::SETTER || tag == LiteralTag::GENERATORMETHOD ||
1292 tag == LiteralTag::ASYNCGENERATORMETHOD) {
1293 auto method_id = EntityId(std::get<uint32_t>(value));
1294 std::string member_func_name = record_name + GetStringByMethodId(method_id);
1295 HandleMemberFunctionFromClassBuf(member_func_name, func, def_class.get());
1296 }
1297 });
1298
1299 return def_class;
1300 }
1301
1302 void AbcFile::ResolveDefineMethodWithBufferInst(Function *func, const Inst &define_class_inst) const
1303 {
1304 auto imms = define_class_inst.GetImms();
1305 auto literal_array_id = EntityId(imms[1]);
1306 std::string record_name = func->GetRecordName();
1307
1308 panda_file::LiteralDataAccessor lit_array_accessor(*panda_file_, panda_file_->GetLiteralArraysId());
1309 lit_array_accessor.EnumerateLiteralVals(
1310 literal_array_id, [&](const panda_file::LiteralDataAccessor::LiteralValue &value, const LiteralTag &tag) {
1311 if (tag == LiteralTag::METHOD || tag == panda_file::LiteralTag::GETTER ||
1312 tag == panda_file::LiteralTag::SETTER || tag == LiteralTag::GENERATORMETHOD ||
1313 tag == LiteralTag::ASYNCGENERATORMETHOD) {
1314 auto method_id = EntityId(std::get<uint32_t>(value));
1315 std::string member_func_name = record_name + GetStringByMethodId(method_id);
1316 Class *def_class = GetClassFromMemberFunctionName(member_func_name);
1317 if (def_class == nullptr) {
1318 LOG(ERROR, DEFECT_SCAN_AUX) << "Unable to find class for private property '" <<
1319 member_func_name << "'";
1320 return;
1321 }
1322 HandleMemberFunctionFromClassBuf(member_func_name, func, def_class);
1323 }
1324 });
1325 }
1326
1327 Class *AbcFile::GetClassFromMemberFunctionName(const std::string &member_func_name) const
1328 {
1329 // The character > indicates the instance function scope of a class
1330 // The character < indicates the static function scope of a class
1331 size_t pos = member_func_name.find_first_of("><");
1332 if (pos == std::string::npos) {
1333 return nullptr;
1334 }
1335 std::string processed_name = member_func_name.substr(0, pos);
1336 // Concatenate constructor prefixes
1337 // The character = represents the constructor scope of a class
1338 processed_name += '=';
1339
1340 std::vector<std::shared_ptr<Class>> class_list = GetClassList();
1341 for (const auto &cls : class_list) {
1342 const std::string &class_name = cls->GetClassName();
1343 if (class_name.find(processed_name) == 0) {
1344 return cls.get();
1345 }
1346 }
1347
1348 return nullptr;
1349 }
1350
1351 std::unique_ptr<CalleeInfo> AbcFile::ResolveCallInstCommon(Function *func, const Inst &call_inst,
1352 uint32_t func_obj_idx) const
1353 {
1354 std::unique_ptr<CalleeInfo> callee_info = std::make_unique<CalleeInfo>(call_inst, func);
1355 if (callee_info == nullptr) {
1356 LOG(FATAL, DEFECT_SCAN_AUX) << "Can not allocate memory when processing '" << filename_ << "'";
1357 }
1358
1359 Inst call_input0 = call_inst.GetInputInsts()[func_obj_idx];
1360 auto [ret_ptr, ret_sym, ret_type] = ResolveInstCommon(func, call_input0);
1361 std::string record_name = func->GetRecordName();
1362 if (ret_ptr != nullptr && ret_type == ResolveType::FUNCTION_OBJECT) {
1363 auto callee = reinterpret_cast<const Function *>(ret_ptr);
1364 callee_info->SetCallee(callee);
1365 } else {
1366 size_t first_delim_idx = ret_sym.find_first_of(DELIM);
1367 size_t last_delim_idx = ret_sym.find_last_of(DELIM);
1368 std::string callee_name = ret_sym;
1369 std::string var_name = EMPTY_STR;
1370 if (first_delim_idx != std::string::npos) {
1371 callee_name = ret_sym.substr(last_delim_idx + 1);
1372 var_name = ret_sym.substr(0, first_delim_idx);
1373 callee_info->SetFunctionName(record_name + callee_name);
1374 }
1375 if (ret_type == ResolveType::UNRESOLVED_MODULE) {
1376 std::string imp_callee_name = GetImportNameByLocalName(callee_name, record_name);
1377 if (!imp_callee_name.empty()) {
1378 callee_info->SetFunctionName(record_name + imp_callee_name);
1379 }
1380 std::string inter_name = var_name.empty() ? callee_name : var_name;
1381 std::string module_name = GetModuleNameByLocalName(inter_name, record_name);
1382 if (!module_name.empty()) {
1383 callee_info->SetExternalModuleName(module_name);
1384 }
1385 } else if (ret_type == ResolveType::UNRESOLVED_GLOBAL_VAR) {
1386 callee_info->SetFunctionName(record_name + callee_name);
1387 var_name = var_name.empty() ? var_name : ret_sym.substr(0, last_delim_idx);
1388 callee_info->SetGlobalVarName(var_name);
1389 }
1390 }
1391 func->AddCalleeInfo(callee_info.get());
1392 return callee_info;
1393 }
1394
1395 std::unique_ptr<CalleeInfo> AbcFile::ResolveSuperCallInst(Function *func, const Inst &call_inst) const
1396 {
1397 std::unique_ptr<CalleeInfo> callee_info = std::make_unique<CalleeInfo>(call_inst, func);
1398 if (callee_info == nullptr) {
1399 LOG(FATAL, DEFECT_SCAN_AUX) << "Can not allocate memory when processing '" << filename_ << "'";
1400 }
1401 const Class *clazz = func->GetClass();
1402 if (clazz != nullptr && clazz->GetParentClass() != nullptr) {
1403 const std::string &parent_ctor_name = clazz->GetParentClass()->GetClassName();
1404 const Function *parent_ctor = GetFunctionByName(parent_ctor_name);
1405 ASSERT(parent_ctor != nullptr);
1406 callee_info->SetCallee(parent_ctor);
1407 }
1408 // TODO(wangyantian): deal with situations when above if doesn't hold
1409 func->AddCalleeInfo(callee_info.get());
1410 return callee_info;
1411 }
1412
1413 void AbcFile::ResolveDefineMethodInst(Function *member_func, const Inst &define_method_inst)
1414 {
1415 std::string record_name = member_func->GetRecordName();
1416 Inst def_method_input0 = define_method_inst.GetInputInsts()[0];
1417 if ((def_method_input0.GetType() == InstType::LDOBJBYNAME_IMM8_ID16 ||
1418 def_method_input0.GetType() == InstType::LDOBJBYNAME_IMM16_ID16) &&
1419 GetStringByInst(def_method_input0) == PROTOTYPE) {
1420 Inst ld_obj_input0 = def_method_input0.GetInputInsts()[0];
1421 if (ld_obj_input0.GetType() == InstType::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8 ||
1422 ld_obj_input0.GetType() == InstType::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8 ||
1423 ld_obj_input0.GetType() == InstType::CALLRUNTIME_DEFINESENDABLECLASS_PREF_IMM16_ID16_ID16_IMM16_V8) {
1424 auto clazz = GetClassByNameImpl(record_name + GetStringByInst(ld_obj_input0));
1425 if (clazz != nullptr) {
1426 BuildClassAndMemberFuncRelation(clazz, member_func);
1427 }
1428 }
1429 }
1430 }
1431
1432 void AbcFile::HandleMemberFunctionFromClassBuf(const std::string &func_name, Function *def_func, Class *def_class) const
1433 {
1434 Function *member_func = GetFunctionByNameImpl(func_name);
1435 ASSERT(member_func != nullptr);
1436 BuildFunctionDefineChain(def_func, member_func);
1437 BuildClassAndMemberFuncRelation(def_class, member_func);
1438 }
1439
1440 void AbcFile::AddDefinedClass(std::shared_ptr<Class> &&def_class)
1441 {
1442 auto &class_name = def_class->GetClassName();
1443 ASSERT(def_class_map_.find(class_name) == def_class_map_.end());
1444 def_class_map_[class_name] = def_class.get();
1445 def_class_list_.emplace_back(std::move(def_class));
1446 }
1447
1448 void AbcFile::AddMergedDefinedClass(std::shared_ptr<Class> &&def_class, std::string record_name)
1449 {
1450 auto &class_name = def_class->GetClassName();
1451 ASSERT(def_class_map_.find(class_name) == def_class_map_.end());
1452 def_class_map_[class_name] = def_class.get();
1453 if (merge_def_class_map_.find(record_name) == merge_def_class_map_.end()) {
1454 merge_def_class_map_.emplace(record_name, std::vector<std::shared_ptr<Class>>());
1455 }
1456 merge_def_class_map_[record_name].push_back(def_class);
1457 merged_def_class_list_.push_back(def_class);
1458 }
1459
1460 void AbcFile::AddDefinedFunction(std::shared_ptr<Function> &&def_func)
1461 {
1462 const std::string &func_name = def_func->GetFunctionName();
1463 ASSERT(def_func_map_.find(func_name) == def_func_map_.end());
1464 def_func_map_[func_name] = def_func.get();
1465 if (func_name != ENTRY_FUNCTION_NAME) {
1466 def_func_list_.emplace_back(std::move(def_func));
1467 } else {
1468 def_func_list_.insert(def_func_list_.begin(), std::move(def_func));
1469 }
1470 }
1471
1472 void AbcFile::AddMergedDefinedFunction(std::shared_ptr<Function> &&def_func)
1473 {
1474 const std::string &record_name = def_func->GetRecordName();
1475 const std::string &func_name = def_func->GetFunctionName();
1476 ASSERT(def_func_map_.find(func_name) == def_func_map_.end());
1477 def_func_map_[func_name] = def_func.get();
1478 merged_def_func_list_.push_back(def_func);
1479 if (merge_def_func_map_.find(record_name) == merge_def_func_map_.end()) {
1480 merge_def_func_map_.emplace(record_name, std::vector<std::shared_ptr<Function>>());
1481 }
1482
1483 if (func_name.find(ENTRY_FUNCTION_NAME) == std::string::npos) {
1484 merge_def_func_map_[record_name].push_back(def_func);
1485 } else {
1486 merge_def_func_map_[record_name].insert(merge_def_func_map_[record_name].begin(), def_func);
1487 }
1488 }
1489
1490 void AbcFile::AddCalleeInfo(std::unique_ptr<CalleeInfo> &&callee_info)
1491 {
1492 callee_info_list_.emplace_back(std::move(callee_info));
1493 }
1494
1495 Function *AbcFile::GetFunctionByNameImpl(std::string_view func_name) const
1496 {
1497 auto iter = def_func_map_.find(std::string(func_name));
1498 if (iter != def_func_map_.end()) {
1499 return iter->second;
1500 }
1501 return nullptr;
1502 }
1503
1504 const ModuleRecord *AbcFile::GetModuleRecordByName(std::string record_name) const
1505 {
1506 if (!IsMergeAbc()) {
1507 record_name = std::string(MODULE_CLASS);
1508 }
1509
1510 auto iter = module_record_map_.find(record_name);
1511 if (iter != module_record_map_.end()) {
1512 return iter->second;
1513 }
1514 return nullptr;
1515 }
1516
1517 Class *AbcFile::GetClassByNameImpl(std::string_view class_name) const
1518 {
1519 auto iter = def_class_map_.find(std::string(class_name));
1520 if (iter != def_class_map_.end()) {
1521 return iter->second;
1522 }
1523 return nullptr;
1524 }
1525
1526 std::string AbcFile::GetStringByMethodId(EntityId method_id) const
1527 {
1528 panda_file::MethodDataAccessor mda {*panda_file_, method_id};
1529 return GetStringByStringId(mda.GetNameId());
1530 }
1531
1532 std::string AbcFile::GetStringByStringId(EntityId string_id) const
1533 {
1534 StringData sd = panda_file_->GetStringData(string_id);
1535 // TODO(wangyantian): what if sd.is_ascii equals false?
1536 return std::string(utf::Mutf8AsCString(sd.data));
1537 }
1538 } // namespace panda::defect_scan_aux
1539