1 /**
2  * Copyright (c) 2021-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 #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() const62     const File *GetFilePtr() const
63     {
64         return file_.get();
65     }
66 
GetItems() const67     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     ClassItem *CreateClassItem(File::EntityId classId);
99     ForeignClassItem *CreateForeignClassItem(File::EntityId classId);
100     MethodHandleItem *CreateMethodHandleItem(File::EntityId mhId);
101     TypeItem *CreateParamTypeItem(ProtoDataAccessor *protoAcc, size_t paramNum, size_t referenceNum);
102     std::vector<MethodParamItem> CreateMethodParamItems(ProtoDataAccessor *protoAcc, MethodDataAccessor *methodAcc,
103                                                         size_t referenceNum);
104     DebugInfoItem *CreateDebugInfoItem(File::EntityId debugInfoId);
105     void UpdateDebugInfoDependecies(File::EntityId debugInfoId);
106     void UpdateDebugInfo(DebugInfoItem *debugInfoItem, File::EntityId debugInfoId);
107 
108     void InstUpdateId(CodeItem *codeItem, MethodItem *methodItem, std::map<BaseItem *, File::EntityId> &reverseDone);
109 
110     bool TryCreateMethodItem(File::EntityId methodId);
111     bool TryCreateFieldItem(File::EntityId fieldId);
112 
113     template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
SetIntegerFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem)114     void SetIntegerFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem)
115     {
116         auto value = fieldAcc->GetValue<T>();
117         if (!value) {
118             return;
119         }
120 
121         // NOLINTNEXTLINE(readability-braces-around-statements)
122         if constexpr (is_same_v<T, int64_t> || is_same_v<T, uint64_t>) {
123             auto *valueItem = container_.GetOrCreateLongValueItem(value.value());
124             fieldItem->SetValue(valueItem);
125             // NOLINTNEXTLINE(readability-misleading-indentation)
126         } else {
127             auto *valueItem = container_.GetOrCreateIntegerValueItem(value.value());
128             fieldItem->SetValue(valueItem);
129         }
130     }
131 
132     template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
SetFloatFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem)133     void SetFloatFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem)
134     {
135         auto value = fieldAcc->GetValue<T>();
136         if (!value) {
137             return;
138         }
139 
140         // NOLINTNEXTLINE(readability-braces-around-statements)
141         if constexpr (is_same_v<T, double>) {
142             auto *valueItem = container_.GetOrCreateDoubleValueItem(value.value());
143             fieldItem->SetValue(valueItem);
144             // NOLINTNEXTLINE(readability-misleading-indentation)
145         } else {
146             auto *valueItem = container_.GetOrCreateFloatValueItem(value.value());
147             fieldItem->SetValue(valueItem);
148         }
149     }
150 
SetStringFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem)151     void SetStringFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem)
152     {
153         auto value = fieldAcc->GetValue<uint32_t>();
154         if (value) {
155             panda_file::File::EntityId stringId(value.value());
156             auto data = file_->GetStringData(stringId);
157             std::string stringData(reinterpret_cast<const char *>(data.data));
158             auto *stringItem = container_.GetOrCreateStringItem(stringData);
159             auto *valueItem = container_.GetOrCreateIdValueItem(stringItem);
160             fieldItem->SetValue(valueItem);
161         }
162     }
163 
164     // Creates foreign or non-foreign method item
CreateGenericMethodItem(BaseClassItem *classItem, File::EntityId methodId)165     inline BaseItem *CreateGenericMethodItem(BaseClassItem *classItem, File::EntityId methodId)
166     {
167         if (file_->IsExternal(methodId)) {
168             return CreateForeignMethodItem(classItem, methodId);
169         }
170         return CreateMethodItem(static_cast<ClassItem *>(classItem), methodId);
171     }
172 
173     // Creates foreign or non-foreign field item
CreateGenericFieldItem(BaseClassItem *classItem, File::EntityId fieldId)174     inline BaseItem *CreateGenericFieldItem(BaseClassItem *classItem, File::EntityId fieldId)
175     {
176         if (file_->IsExternal(fieldId)) {
177             return CreateForeignFieldItem(classItem, fieldId);
178         }
179         return CreateFieldItem(static_cast<ClassItem *>(classItem), fieldId);
180     }
181 
182     // Creates foreign or non-foreign class item
CreateGenericClassItem(File::EntityId classId)183     inline BaseClassItem *CreateGenericClassItem(File::EntityId classId)
184     {
185         if (file_->IsExternal(classId)) {
186             return CreateForeignClassItem(classId);
187         }
188         return CreateClassItem(classId);
189     }
190 
191     void InstCheckByFlags(BytecodeInstruction &inst, MethodItem *methodItem,
192                           const std::map<BaseItem *, File::EntityId> &reverseDone);
193     void UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverseDone);
194 
195     std::unique_ptr<const File> file_;
196     ItemContainer container_;
197     std::map<File::EntityId, BaseItem *> itemsDone_;
198 };
199 
200 }  // namespace ark::panda_file
201 
202 #endif  // LIBPANDAFILE_FILE_READER_H_
203