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