• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 PANDA_LIBPANDAFILE_FILE_H_
17 #define PANDA_LIBPANDAFILE_FILE_H_
18 
19 #include "os/mem.h"
20 #include "utils/span.h"
21 #include "utils/utf.h"
22 
23 #include <cstdint>
24 
25 #include <array>
26 #include <iostream>
27 #include <memory>
28 #include <string>
29 #include <string_view>
30 
31 namespace panda {
32 struct EntryFileStat;
33 }  // namespace panda
34 
35 namespace panda::panda_file {
36 
37 class PandaCache;
38 
39 class File {
40 public:
41     using Index = uint16_t;
42     using Index32 = uint32_t;
43 
44     static constexpr size_t MAGIC_SIZE = 8;
45     static constexpr size_t VERSION_SIZE = 4;
46     static const std::array<uint8_t, MAGIC_SIZE> MAGIC;
47 
48     struct Header {
49         std::array<uint8_t, MAGIC_SIZE> magic;
50         uint32_t checksum;
51         std::array<uint8_t, VERSION_SIZE> version;
52         uint32_t file_size;
53         uint32_t foreign_off;
54         uint32_t foreign_size;
55         uint32_t num_classes;
56         uint32_t class_idx_off;
57         uint32_t num_lnps;
58         uint32_t lnp_idx_off;
59         uint32_t num_literalarrays;
60         uint32_t literalarray_idx_off;
61         uint32_t num_indexes;
62         uint32_t index_section_off;
63     };
64 
65     struct IndexHeader {
66         uint32_t start;
67         uint32_t end;
68         uint32_t class_idx_size;
69         uint32_t class_idx_off;
70         uint32_t method_idx_size;
71         uint32_t method_idx_off;
72         uint32_t field_idx_size;
73         uint32_t field_idx_off;
74         uint32_t proto_idx_size;
75         uint32_t proto_idx_off;
76     };
77 
78     struct StringData {
StringDataStringData79         StringData(uint32_t len, const uint8_t *d) : utf16_length(len), data(d), is_ascii(false) {}
80         StringData() = default;
81         uint32_t utf16_length;  // NOLINT(misc-non-private-member-variables-in-classes)
82         const uint8_t *data;    // NOLINT(misc-non-private-member-variables-in-classes)
83         bool is_ascii;          // NOLINT(misc-non-private-member-variables-in-classes)
84     };
85 
86     // NOLINTNEXTLINE(cppcoreguidelines-special-member-functions, hicpp-special-member-functions)
87     class EntityId {
88     public:
EntityId(uint32_t offset)89         explicit constexpr EntityId(uint32_t offset) : offset_(offset) {}
90 
91         EntityId() = default;
92 
93         ~EntityId() = default;
94 
IsValid()95         bool IsValid() const
96         {
97             return offset_ > sizeof(Header);
98         }
99 
GetOffset()100         uint32_t GetOffset() const
101         {
102             return offset_;
103         }
104 
GetSize()105         static constexpr size_t GetSize()
106         {
107             return sizeof(uint32_t);
108         }
109 
110         friend bool operator==(const EntityId &l, const EntityId &r)
111         {
112             return l.offset_ == r.offset_;
113         }
114 
115         friend std::ostream &operator<<(std::ostream &stream, const EntityId &id)
116         {
117             return stream << id.offset_;
118         }
119 
120     private:
121         uint32_t offset_ {0};
122     };
123 
124     enum OpenMode { READ_ONLY, READ_WRITE };
125 
126     StringData GetStringData(EntityId id) const;
127     EntityId GetLiteralArraysId() const;
128 
129     EntityId GetClassId(const uint8_t *mutf8_name) const;
130 
GetHeader()131     const Header *GetHeader() const
132     {
133         return reinterpret_cast<const Header *>(GetBase());
134     }
135 
GetBase()136     const uint8_t *GetBase() const
137     {
138         return reinterpret_cast<const uint8_t *>(base_.Get());
139     }
140 
GetPtr()141     const os::mem::ConstBytePtr &GetPtr() const
142     {
143         return base_;
144     }
145 
IsExternal(EntityId id)146     bool IsExternal(EntityId id) const
147     {
148         const Header *header = GetHeader();
149         uint32_t foreign_begin = header->foreign_off;
150         uint32_t foreign_end = foreign_begin + header->foreign_size;
151         return id.GetOffset() >= foreign_begin && id.GetOffset() < foreign_end;
152     }
153 
GetIdFromPointer(const uint8_t * ptr)154     EntityId GetIdFromPointer(const uint8_t *ptr) const
155     {
156         return EntityId(ptr - GetBase());
157     }
158 
GetSpanFromId(EntityId id)159     Span<const uint8_t> GetSpanFromId(EntityId id) const
160     {
161         const Header *header = GetHeader();
162         Span file(GetBase(), header->file_size);
163         return file.Last(file.size() - id.GetOffset());
164     }
165 
GetClasses()166     Span<const uint32_t> GetClasses() const
167     {
168         const Header *header = GetHeader();
169         Span file(GetBase(), header->file_size);
170         Span class_idx_data = file.SubSpan(header->class_idx_off, header->num_classes * sizeof(uint32_t));
171         return Span(reinterpret_cast<const uint32_t *>(class_idx_data.data()), header->num_classes);
172     }
173 
GetLiteralArrays()174     Span<const uint32_t> GetLiteralArrays() const
175     {
176         const Header *header = GetHeader();
177         Span file(GetBase(), header->file_size);
178         Span litarr_idx_data = file.SubSpan(header->literalarray_idx_off, header->num_literalarrays * sizeof(uint32_t));
179         return Span(reinterpret_cast<const uint32_t *>(litarr_idx_data.data()), header->num_literalarrays);
180     }
181 
GetIndexHeaders()182     Span<const IndexHeader> GetIndexHeaders() const
183     {
184         const Header *header = GetHeader();
185         Span file(GetBase(), header->file_size);
186         auto sp = file.SubSpan(header->index_section_off, header->num_indexes * sizeof(IndexHeader));
187         return Span(reinterpret_cast<const IndexHeader *>(sp.data()), header->num_indexes);
188     }
189 
GetIndexHeader(EntityId id)190     const IndexHeader *GetIndexHeader(EntityId id) const
191     {
192         auto headers = GetIndexHeaders();
193         auto offset = id.GetOffset();
194         for (const auto &header : headers) {
195             if (header.start <= offset && offset < header.end) {
196                 return &header;
197             }
198         }
199         return nullptr;
200     }
201 
GetClassIndex(EntityId id)202     Span<const EntityId> GetClassIndex(EntityId id) const
203     {
204         auto *header = GetHeader();
205         auto *index_header = GetIndexHeader(id);
206         ASSERT(index_header != nullptr);
207         Span file(GetBase(), header->file_size);
208         auto sp = file.SubSpan(index_header->class_idx_off, index_header->class_idx_size * EntityId::GetSize());
209         return Span(reinterpret_cast<const EntityId *>(sp.data()), index_header->class_idx_size);
210     }
211 
GetMethodIndex(EntityId id)212     Span<const EntityId> GetMethodIndex(EntityId id) const
213     {
214         auto *header = GetHeader();
215         auto *index_header = GetIndexHeader(id);
216         ASSERT(index_header != nullptr);
217         Span file(GetBase(), header->file_size);
218         auto sp = file.SubSpan(index_header->method_idx_off, index_header->method_idx_size * EntityId::GetSize());
219         return Span(reinterpret_cast<const EntityId *>(sp.data()), index_header->method_idx_size);
220     }
221 
GetFieldIndex(EntityId id)222     Span<const EntityId> GetFieldIndex(EntityId id) const
223     {
224         auto *header = GetHeader();
225         auto *index_header = GetIndexHeader(id);
226         ASSERT(index_header != nullptr);
227         Span file(GetBase(), header->file_size);
228         auto sp = file.SubSpan(index_header->field_idx_off, index_header->field_idx_size * EntityId::GetSize());
229         return Span(reinterpret_cast<const EntityId *>(sp.data()), index_header->field_idx_size);
230     }
231 
GetProtoIndex(EntityId id)232     Span<const EntityId> GetProtoIndex(EntityId id) const
233     {
234         auto *header = GetHeader();
235         auto *index_header = GetIndexHeader(id);
236         ASSERT(index_header != nullptr);
237         Span file(GetBase(), header->file_size);
238         auto sp = file.SubSpan(index_header->proto_idx_off, index_header->proto_idx_size * EntityId::GetSize());
239         return Span(reinterpret_cast<const EntityId *>(sp.data()), index_header->proto_idx_size);
240     }
241 
GetLineNumberProgramIndex()242     Span<const EntityId> GetLineNumberProgramIndex() const
243     {
244         const Header *header = GetHeader();
245         Span file(GetBase(), header->file_size);
246         Span lnp_idx_data = file.SubSpan(header->lnp_idx_off, header->num_lnps * EntityId::GetSize());
247         return Span(reinterpret_cast<const EntityId *>(lnp_idx_data.data()), header->num_lnps);
248     }
249 
ResolveClassIndex(EntityId id,Index idx)250     EntityId ResolveClassIndex(EntityId id, Index idx) const
251     {
252         auto index = GetClassIndex(id);
253         return index[idx];
254     }
255 
ResolveMethodIndex(EntityId id,Index idx)256     EntityId ResolveMethodIndex(EntityId id, Index idx) const
257     {
258         auto index = GetMethodIndex(id);
259         return index[idx];
260     }
261 
ResolveFieldIndex(EntityId id,Index idx)262     EntityId ResolveFieldIndex(EntityId id, Index idx) const
263     {
264         auto index = GetFieldIndex(id);
265         return index[idx];
266     }
267 
ResolveProtoIndex(EntityId id,Index idx)268     EntityId ResolveProtoIndex(EntityId id, Index idx) const
269     {
270         auto index = GetProtoIndex(id);
271         return index[idx];
272     }
273 
ResolveLineNumberProgramIndex(Index32 idx)274     EntityId ResolveLineNumberProgramIndex(Index32 idx) const
275     {
276         auto index = GetLineNumberProgramIndex();
277         return index[idx];
278     }
279 
GetFilename()280     const std::string &GetFilename() const
281     {
282         return FILENAME;
283     }
284 
GetPandaCache()285     PandaCache *GetPandaCache() const
286     {
287         return panda_cache_.get();
288     }
289 
GetFilenameHash()290     uint32_t GetFilenameHash() const
291     {
292         return FILENAME_HASH;
293     }
294 
GetUniqId()295     uint64_t GetUniqId() const
296     {
297         return UNIQ_ID;
298     }
299 
300     static uint32_t CalcFilenameHash(const std::string &filename);
301 
302     static std::unique_ptr<const File> Open(std::string_view filename, OpenMode open_mode = READ_ONLY);
303 
304     static std::unique_ptr<const File> OpenFromMemory(os::mem::ConstBytePtr &&ptr);
305 
306     static std::unique_ptr<const File> OpenFromMemory(os::mem::ConstBytePtr &&ptr, std::string_view filename);
307 
308     static std::unique_ptr<const File> OpenUncompressedArchive(int fd, const std::string_view &filename, size_t size,
309                                                                uint32_t offset, OpenMode open_mode = READ_ONLY);
310 
311     ~File();
312 
313     NO_COPY_SEMANTIC(File);
314     NO_MOVE_SEMANTIC(File);
315 
316 private:
317     File(std::string filename, os::mem::ConstBytePtr &&base);
318 
319     const std::string FILENAME;
320     const uint32_t FILENAME_HASH;
321     os::mem::ConstBytePtr base_;
322     std::unique_ptr<PandaCache> panda_cache_;
323     const uint64_t UNIQ_ID;
324 };
325 
326 inline bool operator==(const File::StringData &string_data1, const File::StringData &string_data2)
327 {
328     if (string_data1.utf16_length != string_data2.utf16_length) {
329         return false;
330     }
331 
332     return utf::IsEqual(string_data1.data, string_data2.data);
333 }
334 
335 inline bool operator!=(const File::StringData &string_data1, const File::StringData &string_data2)
336 {
337     return !(string_data1 == string_data2);
338 }
339 
340 /*
341  * OpenPandaFileOrZip from location which specicify the name.
342  */
343 std::unique_ptr<const File> OpenPandaFileOrZip(std::string_view location,
344                                                panda_file::File::OpenMode open_mode = panda_file::File::READ_ONLY);
345 
346 /*
347  * OpenPandaFileFromMemory from file buffer.
348  */
349 std::unique_ptr<const File> OpenPandaFileFromMemory(const void *buffer, size_t size);
350 
351 /*
352  * OpenPandaFile from location which specicify the name.
353  */
354 std::unique_ptr<const File> OpenPandaFile(std::string_view location, std::string_view archive_filename = "",
355                                           panda_file::File::OpenMode open_mode = panda_file::File::READ_ONLY);
356 
357 /*
358  * Check ptr point valid panda file: magic
359  */
360 bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename = "");
361 
362 // NOLINTNEXTLINE(readability-identifier-naming)
363 extern const char *ARCHIVE_FILENAME;
364 }  // namespace panda::panda_file
365 
366 #endif  // PANDA_LIBPANDAFILE_FILE_H_
367