• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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