1 /*
2 * Copyright (c) 2024 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 "collect_util.h"
17
18 namespace panda::libpandafile {
19
20 /**
21 * processed_ids: The literal array ids are collected from field and ins, needn't process nest.
22 * nest_unprocessed_ids: The literal array ids are collected from ins, need process nest.
23 */
CollectLiteralArray(const panda_file::File & file_,std::unordered_set<uint32_t> & processed_ids)24 void CollectUtil::CollectLiteralArray(const panda_file::File &file_, std::unordered_set<uint32_t> &processed_ids)
25 {
26 std::unordered_set<uint32_t> nest_unprocessed_ids;
27
28 for (uint32_t id : file_.GetClasses()) {
29 panda_file::File::EntityId class_id(id);
30 if (file_.IsExternal(class_id)) {
31 continue;
32 }
33 panda_file::ClassDataAccessor class_data_accessor(file_, class_id);
34 CollectClassLiteralArray(class_data_accessor, processed_ids, nest_unprocessed_ids);
35 }
36 ProcessNestLiteralArray(file_, processed_ids, nest_unprocessed_ids);
37 }
38
CollectClassLiteralArray(panda_file::ClassDataAccessor & class_data_accessor,std::unordered_set<uint32_t> & processed_ids,std::unordered_set<uint32_t> & nest_unprocessed_ids)39 void CollectUtil::CollectClassLiteralArray(panda_file::ClassDataAccessor &class_data_accessor,
40 std::unordered_set<uint32_t> &processed_ids,
41 std::unordered_set<uint32_t> &nest_unprocessed_ids)
42 {
43 panda_file::File::StringData csd = class_data_accessor.GetName();
44 const char *cn = utf::Mutf8AsCString(csd.data);
45 class_data_accessor.EnumerateFields([&](panda_file::FieldDataAccessor &field_accessor) -> void {
46 panda_file::File::EntityId field_name_id = field_accessor.GetNameId();
47 panda_file::File::StringData fsd = class_data_accessor.GetPandaFile().GetStringData(field_name_id);
48 const char *fn = utf::Mutf8AsCString(fsd.data);
49 if (std::strcmp(cn, ES_MODULE_RECORD.data()) != 0 &&
50 std::strcmp(cn, ES_SCOPE_NAMES_RECORD.data()) != 0 &&
51 std::strcmp(fn, SCOPE_NAMES.data()) != 0 &&
52 std::strcmp(fn, MODULE_RECORD_IDX.data()) != 0) {
53 return;
54 }
55 auto module_offset = field_accessor.GetValue<uint32_t>().value();
56 processed_ids.emplace(module_offset);
57 });
58 class_data_accessor.EnumerateMethods([&](panda_file::MethodDataAccessor &method_accessor) -> void {
59 if (!method_accessor.GetCodeId().has_value()) {
60 return;
61 }
62 panda_file::File::EntityId method_id = method_accessor.GetMethodId();
63 panda_file::File::EntityId code_id = method_accessor.GetCodeId().value();
64 panda_file::CodeDataAccessor code_data_accessor {class_data_accessor.GetPandaFile(), code_id};
65 uint32_t ins_size_ = code_data_accessor.GetCodeSize();
66 const uint8_t *ins_arr = code_data_accessor.GetInstructions();
67 auto bc_ins = panda::BytecodeInst<BytecodeInstMode::FAST>(ins_arr);
68 const auto bc_ins_last = bc_ins.JumpTo(ins_size_);
69 while (bc_ins.GetAddress() < bc_ins_last.GetAddress()) {
70 if (!bc_ins.IsPrimaryOpcodeValid()) {
71 LOG(FATAL, PANDAFILE) << "Fail to verify primary opcode!";
72 }
73 if (bc_ins.HasFlag(panda::BytecodeInst<BytecodeInstMode::FAST>::Flags::LITERALARRAY_ID)) {
74 const auto literal_id =
75 GetLiteralArrayIdInBytecodeInst(class_data_accessor.GetPandaFile(), method_id, bc_ins);
76 nest_unprocessed_ids.insert(literal_id.GetOffset());
77 }
78 bc_ins = bc_ins.GetNext();
79 }
80 });
81 }
82
ProcessNestLiteralArray(const panda_file::File & file_,std::unordered_set<uint32_t> & processed_ids,std::unordered_set<uint32_t> & nest_unprocessed_ids)83 void CollectUtil::ProcessNestLiteralArray(const panda_file::File &file_, std::unordered_set<uint32_t> &processed_ids,
84 std::unordered_set<uint32_t> &nest_unprocessed_ids)
85 {
86 if (nest_unprocessed_ids.empty()) {
87 return;
88 }
89
90 panda_file::File::EntityId lit_array_invalid(panda_file::INVALID_OFFSET);
91 panda_file::LiteralDataAccessor literal_data_accessor {file_, lit_array_invalid};
92 while (!nest_unprocessed_ids.empty()) {
93 auto nest_unprocess_id_iterator = nest_unprocessed_ids.begin();
94 uint32_t nest_unprocess_id = *nest_unprocess_id_iterator;
95 processed_ids.emplace(nest_unprocess_id);
96 panda_file::File::EntityId nest_unprocess_id_entity_id(nest_unprocess_id);
97 literal_data_accessor.EnumerateLiteralVals(
98 nest_unprocess_id_entity_id,
99 [processed_ids, &nest_unprocessed_ids](const panda_file::LiteralDataAccessor::LiteralValue &value,
100 const panda_file::LiteralTag &tag) {
101 if (tag != panda_file::LiteralTag::LITERALARRAY) {
102 return;
103 }
104 uint32_t idx = std::get<uint32_t>(value);
105 if ((processed_ids.find(idx) != processed_ids.end()) ||
106 (nest_unprocessed_ids.find(idx) != nest_unprocessed_ids.end())) {
107 return;
108 }
109 nest_unprocessed_ids.emplace(idx);
110 });
111 nest_unprocessed_ids.erase(nest_unprocess_id);
112 }
113 }
114
GetLiteralArrayIdInBytecodeInst(const panda_file::File & file_,panda_file::File::EntityId method_id,panda::BytecodeInst<BytecodeInstMode::FAST> bc_ins)115 panda_file::File::EntityId CollectUtil::GetLiteralArrayIdInBytecodeInst(
116 const panda_file::File &file_, panda_file::File::EntityId method_id,
117 panda::BytecodeInst<BytecodeInstMode::FAST> bc_ins)
118 {
119 size_t idx = bc_ins.GetLiteralIndex();
120 if (idx < 0) {
121 LOG(FATAL, PANDAFILE) << "Fail to verify ID Index!";
122 }
123 const auto arg_literal_idx = bc_ins.GetId(idx).AsIndex();
124 const auto literal_id = file_.ResolveMethodIndex(method_id, arg_literal_idx);
125 return literal_id;
126 }
127
128 } // namespace panda::libpandafile