/** * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef LIBPANDAFILE_FILE_READER_H_ #define LIBPANDAFILE_FILE_READER_H_ #include #include "annotation_data_accessor.h" #include "bytecode_instruction.h" #include "class_data_accessor.h" #include "code_data_accessor.h" #include "debug_data_accessor.h" #include "field_data_accessor.h" #include "file_item_container.h" #include "libpandafile/helpers.h" #include "literal_data_accessor.h" #include "method_data_accessor.h" #include "method_handle_data_accessor.h" #include "os/file.h" #include "param_annotations_data_accessor.h" #include "proto_data_accessor.h" #include "utils/pandargs.h" #include "utils/span.h" #include "utils/type_helpers.h" #include "utils/leb128.h" #if !PANDA_TARGET_WINDOWS #include "securec.h" #endif #include #include #include #include namespace ark::panda_file { class FileReader { public: // default methods explicit FileReader(std::unique_ptr &&file) : file_(std::move(file)) {} virtual ~FileReader() = default; bool ReadContainer(bool shouldRebuildIndices = true); ItemContainer *GetContainerPtr() { return &container_; } const File *GetFilePtr() const { return file_.get(); } const std::map *GetItems() const { return &itemsDone_; } void ComputeLayoutAndUpdateIndices(); NO_COPY_SEMANTIC(FileReader); NO_MOVE_SEMANTIC(FileReader); private: bool ReadLiteralArrayItems(); bool ReadRegionHeaders(); bool ReadClasses(); void EmplaceLiteralVals(std::vector &literalArray, const panda_file::LiteralDataAccessor::LiteralValue &value, const panda_file::LiteralTag &tag); bool CreateLiteralArrayItem(LiteralDataAccessor *litArrayAccessor, File::EntityId arrayId, uint32_t index); ValueItem *SetElemValueItem(AnnotationDataAccessor::Tag &annTag, AnnotationDataAccessor::Elem &annElem); AnnotationItem *CreateAnnotationItem(File::EntityId annId); BaseClassItem *GetCatchTypeItem(CodeDataAccessor::CatchBlock &catchBlock, File::EntityId methodId, MethodItem *methodItem); void SetMethodCodeIfPresent(std::optional &codeId, MethodItem *methodItem, File::EntityId &methodId); TypeItem *SetRetType(ProtoDataAccessor &protoAcc, size_t &referenceNum); MethodItem *CreateMethodItem(ClassItem *cls, File::EntityId methodId); ForeignMethodItem *CreateForeignMethodItem(BaseClassItem *fcls, File::EntityId methodId); void SetFieldValue(FieldItem *fieldItem, Type fieldType, FieldDataAccessor &fieldAcc); FieldItem *CreateFieldItem(ClassItem *cls, File::EntityId fieldId); ForeignFieldItem *CreateForeignFieldItem(BaseClassItem *fcls, File::EntityId fieldId); ClassItem *CreateClassItem(File::EntityId classId); ForeignClassItem *CreateForeignClassItem(File::EntityId classId); MethodHandleItem *CreateMethodHandleItem(File::EntityId mhId); TypeItem *CreateParamTypeItem(ProtoDataAccessor *protoAcc, size_t paramNum, size_t referenceNum); std::vector CreateMethodParamItems(ProtoDataAccessor *protoAcc, MethodDataAccessor *methodAcc, size_t referenceNum); DebugInfoItem *CreateDebugInfoItem(File::EntityId debugInfoId); void UpdateDebugInfoDependecies(File::EntityId debugInfoId); void UpdateDebugInfo(DebugInfoItem *debugInfoItem, File::EntityId debugInfoId); void InstUpdateId(CodeItem *codeItem, MethodItem *methodItem, std::map &reverseDone); bool TryCreateMethodItem(File::EntityId methodId); bool TryCreateFieldItem(File::EntityId fieldId); template , bool> = true> void SetIntegerFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem) { auto value = fieldAcc->GetValue(); if (!value) { return; } // NOLINTNEXTLINE(readability-braces-around-statements) if constexpr (is_same_v || is_same_v) { auto *valueItem = container_.GetOrCreateLongValueItem(value.value()); fieldItem->SetValue(valueItem); // NOLINTNEXTLINE(readability-misleading-indentation) } else { auto *valueItem = container_.GetOrCreateIntegerValueItem(value.value()); fieldItem->SetValue(valueItem); } } template , bool> = true> void SetFloatFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem) { auto value = fieldAcc->GetValue(); if (!value) { return; } // NOLINTNEXTLINE(readability-braces-around-statements) if constexpr (is_same_v) { auto *valueItem = container_.GetOrCreateDoubleValueItem(value.value()); fieldItem->SetValue(valueItem); // NOLINTNEXTLINE(readability-misleading-indentation) } else { auto *valueItem = container_.GetOrCreateFloatValueItem(value.value()); fieldItem->SetValue(valueItem); } } void SetStringFieldValue(FieldDataAccessor *fieldAcc, FieldItem *fieldItem) { auto value = fieldAcc->GetValue(); if (value) { panda_file::File::EntityId stringId(value.value()); auto data = file_->GetStringData(stringId); std::string stringData(reinterpret_cast(data.data)); auto *stringItem = container_.GetOrCreateStringItem(stringData); auto *valueItem = container_.GetOrCreateIdValueItem(stringItem); fieldItem->SetValue(valueItem); } } // Creates foreign or non-foreign method item inline BaseItem *CreateGenericMethodItem(BaseClassItem *classItem, File::EntityId methodId) { if (file_->IsExternal(methodId)) { return CreateForeignMethodItem(classItem, methodId); } return CreateMethodItem(static_cast(classItem), methodId); } // Creates foreign or non-foreign field item inline BaseItem *CreateGenericFieldItem(BaseClassItem *classItem, File::EntityId fieldId) { if (file_->IsExternal(fieldId)) { return CreateForeignFieldItem(classItem, fieldId); } return CreateFieldItem(static_cast(classItem), fieldId); } // Creates foreign or non-foreign class item inline BaseClassItem *CreateGenericClassItem(File::EntityId classId) { if (file_->IsExternal(classId)) { return CreateForeignClassItem(classId); } return CreateClassItem(classId); } void InstCheckByFlags(BytecodeInstruction &inst, MethodItem *methodItem, const std::map &reverseDone); void UpdateCodeAndDebugInfoDependencies(const std::map &reverseDone); std::unique_ptr file_; ItemContainer container_; std::map itemsDone_; }; } // namespace ark::panda_file #endif // LIBPANDAFILE_FILE_READER_H_