diff --git a/llvm/include/llvm/BinaryFormat/ADLTSection.h b/llvm/include/llvm/BinaryFormat/ADLTSection.h new file mode 100644 index 0000000000000000000000000000000000000000..6d57903cdd09deae23b0790d0db0237e8b032713 --- /dev/null +++ b/llvm/include/llvm/BinaryFormat/ADLTSection.h @@ -0,0 +1,122 @@ +//===- ADLTSection.h - ADLT Section data types --------------------*- C -*-===// +// +// Copyright (C) 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 LLVM_BINARYFORMAT_ADLTSECTION_H +#define LLVM_BINARYFORMAT_ADLTSECTION_H + +#ifdef __cplusplus +#include + +namespace llvm { +namespace adlt { + +#else // __cplusplus +#include +#endif // __cplusplus + +#ifndef _ELF_H +// part of #include +typedef uint16_t Elf64_Half; +typedef uint64_t Elf64_Off; +typedef uint64_t Elf64_Addr; +typedef uint32_t Elf64_Word; +typedef uint64_t Elf64_Xword; +typedef uint8_t Elf64_Byte; +#endif // _ELF_H + +typedef struct { + Elf64_Word secIndex; + Elf64_Off offset; // from section start +} adlt_cross_section_ref_t; + +typedef struct { + Elf64_Word secIndex; + Elf64_Off offset; // from section start + Elf64_Xword size; // size in bytes +} adlt_cross_section_array_t; + +typedef struct { + Elf64_Off offset; // relative to header.blobStart + Elf64_Xword size; // size in bytes, make convertions for data type +} adlt_blob_array_t; + +// plain-C has no strict typedefs, but aliases used to interpred underlying data +typedef adlt_blob_array_t adlt_blob_u8_array_t; // uint8_t[] +typedef adlt_blob_array_t adlt_blob_u16_array_t; // uint16_t[] +typedef adlt_blob_array_t adlt_blob_u32_array_t; // uint32_t[] +typedef adlt_blob_array_t adlt_blob_u64_array_t; // uint64_t[] + +typedef struct { + Elf64_Half major : 6; + Elf64_Half minor : 6; + Elf64_Half patch : 4; +} adlt_semver_t; + +// DT_NEEDED string index with embedded PSOD index if available +typedef struct { + Elf64_Off hasInternalPSOD : 1; // true if soname + Elf64_Off PSODindex : 16; // PSOD in the current ADLT image + Elf64_Off sonameOffset : 47; // string start in bound .adlt.strtab +} adlt_dt_needed_index_t; + +typedef enum { + ADLT_HASH_TYPE_NONE = 0, + ADLT_HASH_TYPE_GNU_HASH = 1, + ADLT_HASH_TYPE_SYSV_HASH = 2, + ADLT_HASH_TYPE_DEBUG_CONST = 0xfe, + ADLT_HASH_TYPE_MAX = 0xff, +} adlt_hash_type_enum_t; + +typedef uint8_t adlt_hash_type_t; + +// Serializable representation per-shared-object-data in .adlt section +typedef struct { + Elf64_Off soName; // offset in .adlt.strtab + Elf64_Xword soNameHash; // algorithm according to hdr.stringHashType value + adlt_cross_section_array_t initArray; + adlt_cross_section_array_t finiArray; + adlt_blob_array_t dtNeeded; // array of adlt_dt_needed_index_t[] elems + adlt_cross_section_ref_t sharedLocalSymbolIndex; + adlt_cross_section_ref_t sharedGlobalSymbolIndex; + adlt_blob_u16_array_t phIndexes; // program header indexes, typeof(e_phnum) + adlt_blob_u32_array_t relaDynIndx; // .rela.dyn dependent indexes, raw list + adlt_blob_u32_array_t relaPltIndx; // .rela.plt dependent indexes, raw list +} adlt_psod_t; + +typedef struct { + adlt_semver_t schemaVersion; // {major, minor, patch} + Elf64_Half schemaHeaderSize; // >= sizeof(adlt_section_header_t) if comp + Elf64_Half schemaPSODSize; // >= sizeof(adlt_psod_t) if compatible + Elf64_Half sharedObjectsNum; // number of PSOD entries + adlt_hash_type_t stringHashType; // contains adlt_hash_type_enum_t value + Elf64_Off blobStart; // offset of binary blob start relative to .adlt + Elf64_Xword blobSize; + Elf64_Xword overallMappedSize; // bytes, required to map the whole ADLT image + adlt_blob_u16_array_t phIndexes; // program header indexes, typeof(e_phnum) +} adlt_section_header_t; + +static const char adltBlobStartMark[4] = {0xA, 0xD, 0x1, 0x7}; + +static const adlt_semver_t adltSchemaVersion = {1, 1, 0}; + +#ifdef __cplusplus +} // namespace adlt +} // namespace llvm +#endif // __cplusplus + +#endif // LLVM_BINARYFORMAT_ADLTSECTION_H diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 234c946b2014b812c789004bf2c163b594371382..6a12c647f79fb4855b8925e65c4306412b9a3948 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -1391,6 +1391,8 @@ enum { PT_OPENBSD_BOOTDATA = 0x65a41be6, // Section for boot arguments. PT_OHOS_RANDOMDATA = 0x6788FC60, // Fill with random data. OHOS_LOCAL + // OHOS_LOCAL + PT_ADLT = 0x6788FC61, // Adlt information. // ARM program header types. PT_ARM_ARCHEXT = 0x70000000, // Platform architecture compatibility info diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index c9a239f785d2ebceeb33208d8eddf52032dae619..99aa24b6e6c564d8c17201864da1ac0c1921eb58 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -29,6 +29,8 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +// OHOS_LOCAL +#include "llvm/BinaryFormat/ADLTSection.h" #include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/BinaryFormat/MsgPackDocument.h" @@ -353,6 +355,8 @@ protected: void loadDynamicTable(); void parseDynamicTable(); + Expected> findAdlt(); // OHOS_LOCAL + Expected getSymbolVersion(const Elf_Sym &Sym, bool &IsDefault) const; Expected, 0> *> getVersionMap() const; @@ -365,11 +369,16 @@ protected: DynRegionInfo DynSymTabShndxRegion; DynRegionInfo DynamicTable; StringRef DynamicStringTable; + StringRef AdltStringTable; // OHOS_LOCAL const Elf_Hash *HashTable = nullptr; const Elf_GnuHash *GnuHashTable = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; const Elf_Shdr *DotDynsymSec = nullptr; const Elf_Shdr *DotAddrsigSec = nullptr; + // OHOS_LOCAL begin + const Elf_Shdr *DotAdlt = nullptr; + const Elf_Shdr *DotAdltStrtab = nullptr; + // OHOS_LOCAL end DenseMap> ShndxTables; Optional SONameOffset; Optional>> AddressToIndexMap; @@ -388,7 +397,11 @@ protected: Expected getSymbolSectionName(const Elf_Sym &Symbol, unsigned SectionIndex) const; std::string getStaticSymbolName(uint32_t Index) const; + // OHOS_LOCAL + StringRef getDynamicString(uint64_t Value, StringRef StringTable) const; StringRef getDynamicString(uint64_t Value) const; + // OHOS_LOCAL + StringRef getAdltDynamicString(uint64_t Value) const; void printSymbolsHelper(bool IsDynamic) const; std::string getDynamicEntry(uint64_t Type, uint64_t Value) const; @@ -572,6 +585,7 @@ public: void printVersionDefinitionSection(const Elf_Shdr *Sec) override; void printVersionDependencySection(const Elf_Shdr *Sec) override; void printHashHistograms() override; + void printAdltSection() override; // OHOS_LOCAL void printCGProfile() override; void printBBAddrMaps() override; void printAddrsig() override; @@ -676,6 +690,7 @@ public: void printVersionDefinitionSection(const Elf_Shdr *Sec) override; void printVersionDependencySection(const Elf_Shdr *Sec) override; void printHashHistograms() override; + void printAdltSection() override; // OHOS_LOCAL void printCGProfile() override; void printBBAddrMaps() override; void printAddrsig() override; @@ -1416,6 +1431,7 @@ static StringRef segmentTypeToString(unsigned Arch, unsigned Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_BOOTDATA); LLVM_READOBJ_ENUM_CASE(ELF, PT_OHOS_RANDOMDATA); // OHOS_LOCAL + LLVM_READOBJ_ENUM_CASE(ELF, PT_ADLT); // OHOS_LOCAL ADLT info default: return ""; } @@ -1705,6 +1721,48 @@ static const char *getElfMipsOptionsOdkType(unsigned Odk) { } } +// OHOS_LOCAL begin +const EnumEntry AdltHashTypes[] = { + {"None", "NONE", llvm::adlt::ADLT_HASH_TYPE_NONE}, + {"GnuHash", "GNU_HASH", llvm::adlt::ADLT_HASH_TYPE_GNU_HASH}, + {"SysvHash", "SYSV_HASH", llvm::adlt::ADLT_HASH_TYPE_SYSV_HASH}, + {"Debug", "DEBUG", llvm::adlt::ADLT_HASH_TYPE_DEBUG_CONST}, +}; + +template +Expected> ELFDumper::findAdlt() { + // Try to locate .adlt section in the sections table + typename ELFT::ShdrRange Sections = cantFail(Obj.sections()); + for (const Elf_Shdr &Sec : Sections) { + if (DotAdlt && DotAdltStrtab) + break; + + switch (Sec.sh_type) { + case ELF::SHT_STRTAB: + if (!DotAdltStrtab && getPrintableSectionName(Sec) == ".adlt.strtab") + DotAdltStrtab = &Sec; + break; + case ELF::SHT_PROGBITS: + if (!DotAdlt && getPrintableSectionName(Sec) == ".adlt") + DotAdlt = &Sec; + break; + } + } + + if (!DotAdlt) + return createError(".adlt section not found"); + if (!DotAdltStrtab) + return createError("has .adlt but .adlt.strtab section not found"); + + Expected StrTabOrErr = Obj.getStringTable(*DotAdltStrtab); + if (!StrTabOrErr) + return StrTabOrErr.takeError(); + AdltStringTable = *StrTabOrErr; + + return Obj.getSectionContents(*DotAdlt); +} +// OHOS_LOCAL end + template std::pair ELFDumper::findDynamic() { @@ -2399,6 +2457,20 @@ std::string ELFDumper::getDynamicEntry(uint64_t Type, template StringRef ELFDumper::getDynamicString(uint64_t Value) const { + // OHOS_LOCAL + return this->getDynamicString(Value, DynamicStringTable); +} + +// OHOS_LOCAL begin +template +StringRef ELFDumper::getAdltDynamicString(uint64_t Value) const { + return this->getDynamicString(Value, AdltStringTable); +} + +template +StringRef +ELFDumper::getDynamicString(uint64_t Value, + StringRef DynamicStringTable) const { if (DynamicStringTable.empty() && !DynamicStringTable.data()) { reportUniqueWarning("string table was not found"); return ""; @@ -2435,6 +2507,7 @@ StringRef ELFDumper::getDynamicString(uint64_t Value) const { return DynamicStringTable.data() + Value; } +// OHOS_LOCAL end template void ELFDumper::printUnwindInfo() { DwarfCFIEH::PrinterContext Ctx(W, ObjF); @@ -4822,6 +4895,12 @@ template void GNUELFDumper::printHashHistograms() { } } +// OHOS_LOCAL begin +template void GNUELFDumper::printAdltSection() { + OS << "GNUStyle::printAdltSection not implemented\n"; +} +// OHOS_LOCAL end + template void GNUELFDumper::printCGProfile() { OS << "GNUStyle::printCGProfile not implemented\n"; } @@ -6954,6 +7033,205 @@ template void LLVMELFDumper::printHashHistograms() { W.startLine() << "Hash Histogram not implemented!\n"; } +// OHOS_LOCAL begin +template void LLVMELFDumper::printAdltSection() { + using namespace llvm::adlt; + constexpr size_t kBinDumpLimit = sizeof(Elf64_Xword) * 0x80; + + Expected> ContentsOrErr = this->findAdlt(); + if (!ContentsOrErr) { + return this->reportUniqueWarning(ContentsOrErr.takeError()); + } + + ArrayRef adltRaw = ContentsOrErr.get(); + auto *header = + reinterpret_cast(adltRaw.data()); + const auto &ver = header->schemaVersion; + + ArrayRef psodsRaw; + ArrayRef blob; + + if (psodsRaw.data() + psodsRaw.size() > blob.data()) + return this->reportUniqueWarning("invalid .adlt section: " + "PSOD and blob entries are overlapped"); + if (blob.data() + blob.size() > adltRaw.data() + adltRaw.size()) + return this->reportUniqueWarning("invalid .adlt section: " + "blob is out of section range"); + + DictScope DSec(W, "ADLT"); + + do { + DictScope DHeader(W, "Header"); + W.printVersion("schema-version", ver.major, ver.minor, ver.patch); + + if (ver.major > 1) { + this->reportUniqueWarning(Twine("schema version not supported yet")); + return; + } + + W.printHex("schema-header-size", header->schemaHeaderSize); + W.printHex("schema-psod-size", header->schemaPSODSize); + W.printNumber("shared-objects-num", header->sharedObjectsNum); + W.printEnum("string-hash-type", header->stringHashType, + makeArrayRef(AdltHashTypes)); + W.printHex("blob-start", header->blobStart); + W.printHex("blob-size", header->blobSize); + W.printHex("overall-mapped-size", header->overallMappedSize); + + psodsRaw = adltRaw.slice(header->schemaHeaderSize, + header->sharedObjectsNum * header->schemaPSODSize); + blob = adltRaw.slice(header->blobStart, header->blobSize); + + if (psodsRaw.data() + psodsRaw.size() > blob.data()) + return this->reportUniqueWarning("invalid .adlt section: " + "PSOD and blob entries are overlapped"); + if (blob.data() + blob.size() > adltRaw.data() + adltRaw.size()) + return this->reportUniqueWarning("invalid .adlt section: " + "blob is out of section range"); + + if (ver.minor >= 1) { + DictScope PHEntry(W, "ph-indexes"); + const auto &arr = header->phIndexes; + W.printHex("size", arr.size); + W.printHex("offset", arr.offset); + + const auto chunk = blob.slice(arr.offset, arr.size); + if (!chunk.empty()) { + W.printBinary("raw", chunk); + ArrayRef phIdxs( + reinterpret_cast(chunk.data()), + chunk.size() / sizeof(uint16_t)); + W.printList("values", phIdxs); + } + } + } while (0); + + { + ListScope LPsods(W, "PSODs"); + + for (size_t psodIdx = 0; psodIdx < header->sharedObjectsNum; ++psodIdx) { + const adlt_psod_t &psod = *reinterpret_cast( + psodsRaw.data() + psodIdx * header->schemaPSODSize); + + auto psodName = Twine("psod-#") + Twine(psodIdx); + DictScope LEntry(W, psodName.str()); + + { + DictScope MetaEntry(W, "$-meta"); + auto psodSuffix = Twine("__") + Twine::utohexstr(psodIdx); + W.printNumber("$-order", psodIdx); + W.printString("$-symbol-suffix", psodSuffix.str()); + } + + W.printString("soname", this->getAdltDynamicString(psod.soName)); + W.printHex("soname-hash", psod.soNameHash); + { + DictScope IAEntry(W, "init-array"); + W.printHex("size", psod.initArray.size); + W.printNumber("sec-index", psod.initArray.secIndex); + W.printHex("offset", psod.initArray.offset); + } + { + DictScope IAEntry(W, "fini-array"); + W.printHex("size", psod.finiArray.size); + W.printNumber("sec-index", psod.finiArray.secIndex); + W.printHex("offset", psod.finiArray.offset); + } + { + DictScope DNEntry(W, "dt-needed"); + const auto &arr = psod.dtNeeded; + W.printHex("size", arr.size); + W.printHex("offset", arr.offset); + + const auto chunk = blob.slice(arr.offset, arr.size); + if (!chunk.empty()) { + W.printBinary("raw", chunk); + + ArrayRef deps( + reinterpret_cast(chunk.data()), + chunk.size() / sizeof(adlt_dt_needed_index_t)); + + ListScope NeedList(W, "needed-libs"); + for (const auto &need : deps) { + DictScope DepEntry(W, + this->getAdltDynamicString(need.sonameOffset)); + W.printBoolean("is-internal", need.hasInternalPSOD); + if (need.hasInternalPSOD) + W.printNumber("psod-id", need.PSODindex); + } + } + } + { + DictScope SLEntry(W, "shared-local-symbol"); + const auto &csref = psod.sharedLocalSymbolIndex; + W.printNumber("sec-index", csref.secIndex); + W.printHex("offset", csref.offset); + } + { + DictScope SGEntry(W, "shared-global-symbol"); + const auto &csref = psod.sharedGlobalSymbolIndex; + W.printNumber("sec-index", csref.secIndex); + W.printHex("offset", csref.offset); + } + { + DictScope PHEntry(W, "ph-indexes"); + const auto &arr = psod.phIndexes; + W.printHex("size", arr.size); + W.printHex("offset", arr.offset); + + const auto chunk = blob.slice(arr.offset, arr.size); + if (!chunk.empty()) { + W.printBinary("raw", chunk); + ArrayRef phIdxs( + reinterpret_cast(chunk.data()), + chunk.size() / sizeof(uint16_t)); + W.printList("values", phIdxs); + } + } + { + DictScope RDEntry(W, "rela-dyn-idxs"); + const auto &arr = psod.relaDynIndx; + W.printHex("size", arr.size); + W.printHex("offset", arr.offset); + + const auto chunk = blob.slice(arr.offset, arr.size); + if (!chunk.empty()) { + if (chunk.size() > kBinDumpLimit) + W.printString("raw", ""); + else + W.printBinary("raw", chunk); + } + } + { + DictScope RPEntry(W, "rela-plt-idsx"); + const auto &arr = psod.relaPltIndx; + W.printHex("size", arr.size); + W.printHex("offset", arr.offset); + + const auto chunk = blob.slice(arr.offset, arr.size); + if (!chunk.empty()) { + if (chunk.size() > kBinDumpLimit) + W.printString("raw", ""); + else + W.printBinary("raw", chunk); + } + } + } + } + + { + DictScope DBlob(W, "Blob"); + W.printHex("start", header->blobStart); + W.printHex("size", header->blobSize); + + if (blob.size() > kBinDumpLimit * 50) + W.printString("raw", ""); + else + W.printBinaryBlock("raw", blob); + } +} +// OHOS_LOCAL end + // Returns true if rel/rela section exists, and populates SymbolIndices. // Otherwise returns false. template diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h index 292efd2ae350a77cda3cc50fb0c1a7d1c6201f28..bad21cc732b21e0542f1b0bdd6fa9af549380dbd 100644 --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -129,6 +129,7 @@ public: virtual void printVersionInfo() {} virtual void printGroupSections() {} virtual void printHashHistograms() {} + virtual void printAdltSection() {} // OHOS_LOCAL virtual void printCGProfile() {} virtual void printBBAddrMaps() {} virtual void printAddrsig() {} diff --git a/llvm/tools/llvm-readobj/Opts.td b/llvm/tools/llvm-readobj/Opts.td index 4687fc71245f8478e6f0f25b3fa2e5dcc16b3b77..2abd661af548b7c91f49d1b86bace658ac139594 100644 --- a/llvm/tools/llvm-readobj/Opts.td +++ b/llvm/tools/llvm-readobj/Opts.td @@ -55,6 +55,8 @@ def section_groups : FF<"section-groups", "Display section groups">, Group, Group; def hash_symbols : FF<"hash-symbols", "Display the dynamic symbols derived from the hash section">, Group; def hash_table : FF<"hash-table", "Display .hash section">, Group; +// OHOS_LOCAL +def adlt_section: FF<"adlt-section", "Display .adlt section in a pretty format">, Group; def needed_libs : FF<"needed-libs", "Display the needed libraries">, Group; def notes : FF<"notes", "Display notes">, Group; def program_headers : FF<"program-headers", "Display program headers">, Group; diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index e1ebbeb41f28b02e31ef3f28fbdfed6e687cff01..b4c1d7dd94b7953bfaf24f3f73b48ef146a51171 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -125,6 +125,7 @@ static cl::boolOrDefault SectionMapping; static SmallVector SortKeys; // ELF specific options. +static bool AdltSection; // OHOS_LOCAL static bool DynamicTable; static bool ELFLinkerOptions; static bool GnuHashTable; @@ -253,6 +254,8 @@ static void parseOptions(const opt::InputArgList &Args) { OutputStyleChoice + "'"); } } + // OHOS_LOCAL + opts::AdltSection = Args.hasArg(OPT_adlt_section); opts::GnuHashTable = Args.hasArg(OPT_gnu_hash_table); opts::HashSymbols = Args.hasArg(OPT_hash_symbols); opts::HashTable = Args.hasArg(OPT_hash_table); @@ -449,6 +452,10 @@ static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer, Dumper->printGroupSections(); if (opts::HashHistogram) Dumper->printHashHistograms(); + // OHOS_LOCAL begin + if (opts::AdltSection) + Dumper->printAdltSection(); + // OHOS_LOCAL end if (opts::CGProfile) Dumper->printCGProfile(); if (opts::BBAddrMap)