• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 #ifndef LIBPANDAFILE_FILE_READER_H_
16 #define LIBPANDAFILE_FILE_READER_H_
17 
18 #include <type_traits>
19 #include "annotation_data_accessor.h"
20 #include "bytecode_instruction.h"
21 #include "class_data_accessor.h"
22 #include "code_data_accessor.h"
23 #include "debug_data_accessor.h"
24 #include "field_data_accessor.h"
25 #include "file_item_container.h"
26 #include "libpandafile/helpers.h"
27 #include "literal_data_accessor.h"
28 #include "method_data_accessor.h"
29 #include "method_handle_data_accessor.h"
30 #include "os/file.h"
31 #include "param_annotations_data_accessor.h"
32 #include "proto_data_accessor.h"
33 #include "utils/pandargs.h"
34 #include "utils/span.h"
35 #include "utils/type_helpers.h"
36 #include "utils/leb128.h"
37 #if !PANDA_TARGET_WINDOWS
38 #include "securec.h"
39 #endif
40 
41 #include <cstdint>
42 #include <cerrno>
43 
44 #include <limits>
45 #include <vector>
46 
47 namespace ark::panda_file {
48 
49 class FileReader {
50 public:
51     // default methods
FileReader(std::unique_ptr<const File> && file)52     explicit FileReader(std::unique_ptr<const File> &&file) : file_(std::move(file)) {}
53     virtual ~FileReader() = default;
54 
55     bool ReadContainer(bool shouldRebuildIndices = true);
56 
GetContainerPtr()57     ItemContainer *GetContainerPtr()
58     {
59         return &container_;
60     }
61 
GetFilePtr()62     const File *GetFilePtr() const
63     {
64         return file_.get();
65     }
66 
GetItems()67     const std::map<File::EntityId, BaseItem *> *GetItems() const
68     {
69         return &itemsDone_;
70     }
71 
72     void ComputeLayoutAndUpdateIndices();
73 
74     NO_COPY_SEMANTIC(FileReader);
75     NO_MOVE_SEMANTIC(FileReader);
76 
77 private:
78     bool ReadLiteralArrayItems();
79     bool ReadRegionHeaders();
80     bool ReadClasses();
81 
82     void EmplaceLiteralVals(std::vector<panda_file::LiteralItem> &literalArray,
83                             const panda_file::LiteralDataAccessor::LiteralValue &value,
84                             const panda_file::LiteralTag &tag);
85     bool CreateLiteralArrayItem(LiteralDataAccessor *litArrayAccessor, File::EntityId arrayId, uint32_t index);
86     ValueItem *SetElemValueItem(AnnotationDataAccessor::Tag &annTag, AnnotationDataAccessor::Elem &annElem);
87     AnnotationItem *CreateAnnotationItem(File::EntityId annId);
88     BaseClassItem *GetCatchTypeItem(CodeDataAccessor::CatchBlock &catchBlock, File::EntityId methodId,
89                                     MethodItem *methodItem);
90     void SetMethodCodeIfPresent(std::optional<File::EntityId> &codeId, MethodItem *methodItem,
91                                 File::EntityId &methodId);
92     TypeItem *SetRetType(ProtoDataAccessor &protoAcc, size_t &referenceNum);
93     MethodItem *CreateMethodItem(ClassItem *cls, File::EntityId methodId);
94     ForeignMethodItem *CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId methodId);
95     void SetFieldValue(FieldItem *fieldItem, Type fieldType, FieldDataAccessor &fieldAcc);
96     FieldItem *CreateFieldItem(ClassItem *cls, File::EntityId fieldId);
97     ForeignFieldItem *CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId fieldId);
98     BaseItem *CheckAndGetExistingFileItem(File::EntityId id, ItemTypes itemType);
99     ClassItem *CreateClassItem(File::EntityId classId);
100     ForeignClassItem *CreateForeignClassItem(File::EntityId classId);
101     MethodHandleItem *CreateMethodHandleItem(File::EntityId mhId);
102     TypeItem *CreateParamTypeItem(ProtoDataAccessor *protoAcc, size_t paramNum, size_t referenceNum);
103     std::vector<MethodParamItem> CreateMethodParamItems(ProtoDataAccessor *protoAcc, MethodDataAccessor *methodAcc,
104                                                         size_t referenceNum);
105     DebugInfoItem *CreateDebugInfoItem(File::EntityId debugInfoId);
106     void UpdateDebugInfoDependecies(File::EntityId debugInfoId);
107     void UpdateDebugInfo(DebugInfoItem *debugInfoItem, File::EntityId debugInfoId);
108 
109     void InstUpdateId(CodeItem *codeItem, MethodItem *methodItem, std::map<BaseItem *, File::EntityId> &reverseDone);
110 
111     bool TryCreateMethodItem(File::EntityId methodId);
112     bool TryCreateFieldItem(File::EntityId fieldId);
113 
114     template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
SetIntegerFieldValue(FieldDataAccessor * fieldAcc,FieldItem * fieldItem)115     void SetIntegerFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem)
116     {
117         auto value = fieldAcc->GetValue<T>();
118         if (!value) {
119             return;
120         }
121 
122         // NOLINTNEXTLINE(readability-braces-around-statements)
123         if constexpr (is_same_v<T, int64_t> || is_same_v<T, uint64_t>) {
124             auto *valueItem = container_.GetOrCreateLongValueItem(value.value());
125             fieldItem->SetValue(valueItem);
126             // NOLINTNEXTLINE(readability-misleading-indentation)
127         } else {
128             auto *valueItem = container_.GetOrCreateIntegerValueItem(value.value());
129             fieldItem->SetValue(valueItem);
130         }
131     }
132 
133     template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
SetFloatFieldValue(FieldDataAccessor * fieldAcc,FieldItem * fieldItem)134     void SetFloatFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem)
135     {
136         auto value = fieldAcc->GetValue<T>();
137         if (!value) {
138             return;
139         }
140 
141         // NOLINTNEXTLINE(readability-braces-around-statements)
142         if constexpr (is_same_v<T, double>) {
143             auto *valueItem = container_.GetOrCreateDoubleValueItem(value.value());
144             fieldItem->SetValue(valueItem);
145             // NOLINTNEXTLINE(readability-misleading-indentation)
146         } else {
147             auto *valueItem = container_.GetOrCreateFloatValueItem(value.value());
148             fieldItem->SetValue(valueItem);
149         }
150     }
151 
SetStringFieldValue(FieldDataAccessor * fieldAcc,FieldItem * fieldItem)152     void SetStringFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem)
153     {
154         auto value = fieldAcc->GetValue<uint32_t>();
155         if (value) {
156             panda_file::File::EntityId stringId(value.value());
157             auto data = file_->GetStringData(stringId);
158             std::string stringData(reinterpret_cast<const char *>(data.data));
159             auto *stringItem = container_.GetOrCreateStringItem(stringData);
160             auto *valueItem = container_.GetOrCreateIdValueItem(stringItem);
161             fieldItem->SetValue(valueItem);
162         }
163     }
164 
165     // Creates foreign or non-foreign method item
CreateGenericMethodItem(BaseClassItem * classItem,File::EntityId methodId)166     inline BaseItem *CreateGenericMethodItem(BaseClassItem *classItem, File::EntityId methodId)
167     {
168         if (file_->IsExternal(methodId)) {
169             return CreateForeignMethodItem(classItem, methodId);
170         }
171         LOG_IF(classItem->IsForeign(), FATAL, PANDAFILE) << "Non-foreign methods should not belong to foreign class.";
172         return CreateMethodItem(static_cast<ClassItem *>(classItem), methodId);
173     }
174 
175     // Creates foreign or non-foreign field item
CreateGenericFieldItem(BaseClassItem * classItem,File::EntityId fieldId)176     inline BaseItem *CreateGenericFieldItem(BaseClassItem *classItem, File::EntityId fieldId)
177     {
178         if (file_->IsExternal(fieldId)) {
179             return CreateForeignFieldItem(classItem, fieldId);
180         }
181         LOG_IF(classItem->IsForeign(), FATAL, PANDAFILE) << "Non-foreign fields should not belong to foreign class.";
182         return CreateFieldItem(static_cast<ClassItem *>(classItem), fieldId);
183     }
184 
185     // Creates foreign or non-foreign class item
CreateGenericClassItem(File::EntityId classId)186     inline BaseClassItem *CreateGenericClassItem(File::EntityId classId)
187     {
188         if (file_->IsExternal(classId)) {
189             return CreateForeignClassItem(classId);
190         }
191         return CreateClassItem(classId);
192     }
193 
194     void InstCheckByFlags(BytecodeInstruction &inst, MethodItem *methodItem,
195                           const std::map<BaseItem *, File::EntityId> &reverseDone);
196     void UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverseDone);
197 
198     std::unique_ptr<const File> file_;
199     ItemContainer container_;
200     std::map<File::EntityId, BaseItem *> itemsDone_;
201 };
202 
203 }  // namespace ark::panda_file
204 
205 #endif  // LIBPANDAFILE_FILE_READER_H_
206