1 /**
2  * Copyright (c) 2021-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 #ifndef LIBPANDAFILE_FILE_READER_H
17 #define LIBPANDAFILE_FILE_READER_H
18 
19 #include <type_traits>
20 #include "annotation_data_accessor.h"
21 #include "bytecode_instruction.h"
22 #include "class_data_accessor.h"
23 #include "code_data_accessor.h"
24 #include "debug_data_accessor.h"
25 #include "field_data_accessor.h"
26 #include "file_item_container.h"
27 #include "libpandafile/helpers.h"
28 #include "literal_data_accessor.h"
29 #include "method_data_accessor.h"
30 #include "method_handle_data_accessor.h"
31 #include "os/file.h"
32 #include "param_annotations_data_accessor.h"
33 #include "proto_data_accessor.h"
34 #include "utils/pandargs.h"
35 #include "utils/span.h"
36 #include "utils/type_helpers.h"
37 #include "utils/leb128.h"
38 #if !PANDA_TARGET_WINDOWS
39 #include "securec.h"
40 #endif
41 
42 #include <cstdint>
43 #include <cerrno>
44 
45 #include <limits>
46 #include <vector>
47 
48 namespace panda::panda_file {
49 
50 class FileReader {
51 public:
52     // default methods
FileReader(std::unique_ptr<const File> &&file)53     explicit FileReader(std::unique_ptr<const File> &&file) : file_(std::move(file)) {}
54     virtual ~FileReader() = default;
55 
56     bool ReadContainer();
57 
GetContainerPtr()58     ItemContainer *GetContainerPtr()
59     {
60         return &container_;
61     }
62 
63     void ComputeLayoutAndUpdateIndices();
64 
65     NO_COPY_SEMANTIC(FileReader);
66     NO_MOVE_SEMANTIC(FileReader);
67 
68 private:
69     bool ReadLiteralArrayItems();
70     bool ReadIndexHeaders();
71     bool ReadClasses();
72 
73     bool CreateLiteralArrayItem(const LiteralDataAccessor::LiteralValue &lit_value, const LiteralTag &tag,
74                                 File::EntityId array_id);
75     AnnotationItem *CreateAnnotationItem(File::EntityId ann_id);
76     MethodItem *CreateMethodItem(ClassItem *cls, File::EntityId method_id);
77     ForeignMethodItem *CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId method_id);
78     FieldItem *CreateFieldItem(ClassItem *cls, File::EntityId field_id);
79     ForeignFieldItem *CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId field_id);
80     ClassItem *CreateClassItem(File::EntityId class_id);
81     ForeignClassItem *CreateForeignClassItem(File::EntityId class_id);
82     MethodHandleItem *CreateMethodHandleItem(File::EntityId mh_id);
83     TypeItem *CreateParamTypeItem(ProtoDataAccessor *proto_acc, size_t param_num, size_t reference_num);
84     TypeItem *GetReturnTypeItem(Type type, size_t &reference_num);
85     std::vector<MethodParamItem> CreateMethodParamItems(ProtoDataAccessor *proto_acc, MethodDataAccessor *method_acc,
86                                                         size_t reference_num);
87     DebugInfoItem *CreateDebugInfoItem(File::EntityId debug_info_id);
88     void EnumerateBlocks(MethodDataAccessor method_acc, MethodItem *method_item);
89     void UpdateDebugInfoDependecies(File::EntityId debug_info_id);
90     void UpdateDebugInfo(DebugInfoItem *debug_info_item, File::EntityId debug_info_id);
91     void CreateSuperClassItem(ClassDataAccessor& class_acc, ClassItem* class_item, const std::string& class_name);
92     void AddIndexDependencyInstFlag(CodeItem *code_item, MethodItem *method_item,
93                                     const std::unordered_map<File::EntityId, File::EntityId> &reverse_done);
94     void UpdateIdInstFlag(CodeItem *code_item, MethodItem *method_item,
95                           const std::unordered_map<File::EntityId, File::EntityId> &reverse_done);
96 
97     template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
SetIntegerFieldValue(FieldDataAccessor *field_acc, FieldItem *field_item)98     void SetIntegerFieldValue(FieldDataAccessor *field_acc, FieldItem *field_item)
99     {
100         auto value = field_acc->GetValue<T>();
101         if (!value) {
102             return;
103         }
104 
105         // NOLINTNEXTLINE(readability-braces-around-statements)
106         if constexpr (is_same_v<T, int64_t> || is_same_v<T, uint64_t>) {
107             auto *value_item = container_.GetOrCreateLongValueItem(value.value());
108             field_item->SetValue(value_item);
109             // NOLINTNEXTLINE(readability-misleading-indentation)
110         } else {
111             auto *value_item = container_.GetOrCreateIntegerValueItem(value.value());
112             field_item->SetValue(value_item);
113         }
114     }
115 
116     template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
SetFloatFieldValue(FieldDataAccessor *field_acc, FieldItem *field_item)117     void SetFloatFieldValue(FieldDataAccessor *field_acc, FieldItem *field_item)
118     {
119         auto value = field_acc->GetValue<T>();
120         if (!value) {
121             return;
122         }
123 
124         // NOLINTNEXTLINE(readability-braces-around-statements)
125         if constexpr (is_same_v<T, double>) {
126             auto *value_item = container_.GetOrCreateDoubleValueItem(value.value());
127             field_item->SetValue(value_item);
128             // NOLINTNEXTLINE(readability-misleading-indentation)
129         } else {
130             auto *value_item = container_.GetOrCreateFloatValueItem(value.value());
131             field_item->SetValue(value_item);
132         }
133     }
134 
SetStringFieldValue(FieldDataAccessor *field_acc, FieldItem *field_item)135     void SetStringFieldValue(FieldDataAccessor *field_acc, FieldItem *field_item)
136     {
137         auto value = field_acc->GetValue<uint32_t>();
138         if (value) {
139             panda_file::File::EntityId string_id(value.value());
140             auto data = file_->GetStringData(string_id);
141             std::string string_data(reinterpret_cast<const char *>(data.data));
142             auto *string_item = container_.GetOrCreateStringItem(string_data);
143             auto *value_item = container_.GetOrCreateIdValueItem(string_item);
144             field_item->SetValue(value_item);
145         }
146     }
147 
148     // Creates foreign or non-foreign method item
CreateGenericMethodItem(BaseClassItem *class_item, File::EntityId method_id)149     inline BaseItem *CreateGenericMethodItem(BaseClassItem *class_item, File::EntityId method_id)
150     {
151         if (file_->IsExternal(method_id)) {
152             return CreateForeignMethodItem(class_item, method_id);
153         }
154         return CreateMethodItem(static_cast<ClassItem *>(class_item), method_id);
155     }
156 
157     // Creates foreign or non-foreign field item
CreateGenericFieldItem(BaseClassItem *class_item, File::EntityId field_id)158     inline BaseItem *CreateGenericFieldItem(BaseClassItem *class_item, File::EntityId field_id)
159     {
160         if (file_->IsExternal(field_id)) {
161             return CreateForeignFieldItem(class_item, field_id);
162         }
163         return CreateFieldItem(static_cast<ClassItem *>(class_item), field_id);
164     }
165 
166     // Creates foreign or non-foreign class item
CreateGenericClassItem(File::EntityId class_id)167     inline BaseClassItem *CreateGenericClassItem(File::EntityId class_id)
168     {
169         if (file_->IsExternal(class_id)) {
170             return CreateForeignClassItem(class_id);
171         }
172         return CreateClassItem(class_id);
173     }
174 
175     void UpdateCodeAndDebugInfoDependencies(const std::map<BaseItem *, File::EntityId> &reverse_done);
176 
177     std::unique_ptr<const File> file_;
178     ItemContainer container_;
179     std::map<File::EntityId, BaseItem *> items_done_;
180 };
181 
182 }  // namespace panda::panda_file
183 
184 #endif  // LIBPANDAFILE_FILE_READER_H
185