[llvm] 05d8d64 - [llvm-readobj] Add support for dumping CHPE metadata.

Jacek Caban via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 30 05:58:36 PDT 2023


Author: Jacek Caban
Date: 2023-06-30T14:57:10+02:00
New Revision: 05d8d6405ef10a81c3d2bc9da53665221a8a9f1b

URL: https://github.com/llvm/llvm-project/commit/05d8d6405ef10a81c3d2bc9da53665221a8a9f1b
DIFF: https://github.com/llvm/llvm-project/commit/05d8d6405ef10a81c3d2bc9da53665221a8a9f1b.diff

LOG: [llvm-readobj] Add support for dumping CHPE metadata.

CHPE metadata is used by ARM64EC/ARM64X PE files to provide metadata for
emulator/loader. Most of this metadata will need to be generated by LLD.

Differential Revision: https://reviews.llvm.org/D149089

Added: 
    llvm/test/tools/llvm-readobj/arm64ec-chpe.yaml

Modified: 
    llvm/include/llvm/Object/COFF.h
    llvm/lib/Object/COFFObjectFile.cpp
    llvm/tools/llvm-readobj/COFFDumper.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h
index fa90c58f1836ab..e6a607921da0ef 100644
--- a/llvm/include/llvm/Object/COFF.h
+++ b/llvm/include/llvm/Object/COFF.h
@@ -722,6 +722,47 @@ struct coff_load_configuration64 {
   support::ulittle64_t CastGuardOsDeterminedFailureMode;
 };
 
+struct chpe_metadata {
+  support::ulittle32_t Version;
+  support::ulittle32_t CodeMap;
+  support::ulittle32_t CodeMapCount;
+  support::ulittle32_t CodeRangesToEntryPoints;
+  support::ulittle32_t RedirectionMetadata;
+  support::ulittle32_t __os_arm64x_dispatch_call_no_redirect;
+  support::ulittle32_t __os_arm64x_dispatch_ret;
+  support::ulittle32_t __os_arm64x_dispatch_call;
+  support::ulittle32_t __os_arm64x_dispatch_icall;
+  support::ulittle32_t __os_arm64x_dispatch_icall_cfg;
+  support::ulittle32_t AlternateEntryPoint;
+  support::ulittle32_t AuxiliaryIAT;
+  support::ulittle32_t CodeRangesToEntryPointsCount;
+  support::ulittle32_t RedirectionMetadataCount;
+  support::ulittle32_t GetX64InformationFunctionPointer;
+  support::ulittle32_t SetX64InformationFunctionPointer;
+  support::ulittle32_t ExtraRFETable;
+  support::ulittle32_t ExtraRFETableSize;
+  support::ulittle32_t __os_arm64x_dispatch_fptr;
+  support::ulittle32_t AuxiliaryIATCopy;
+};
+
+struct chpe_range_entry {
+  support::ulittle32_t StartOffset;
+  support::ulittle32_t Length;
+};
+
+enum chpe_range_type { CHPE_RANGE_ARM64, CHPE_RANGE_ARM64EC, CHPE_RANGE_AMD64 };
+
+struct chpe_code_range_entry {
+  support::ulittle32_t StartRva;
+  support::ulittle32_t EndRva;
+  support::ulittle32_t EntryPoint;
+};
+
+struct chpe_redirection_entry {
+  support::ulittle32_t Source;
+  support::ulittle32_t Destination;
+};
+
 struct coff_runtime_function_x64 {
   support::ulittle32_t BeginAddress;
   support::ulittle32_t EndAddress;
@@ -813,6 +854,7 @@ class COFFObjectFile : public ObjectFile {
   const coff_tls_directory64 *TLSDirectory64;
   // Either coff_load_configuration32 or coff_load_configuration64.
   const void *LoadConfig = nullptr;
+  const chpe_metadata *CHPEMetadata = nullptr;
 
   Expected<StringRef> getString(uint32_t offset) const;
 
@@ -927,6 +969,9 @@ class COFFObjectFile : public ObjectFile {
     assert(is64());
     return reinterpret_cast<const coff_load_configuration64 *>(LoadConfig);
   }
+
+  const chpe_metadata *getCHPEMetadata() const { return CHPEMetadata; }
+
   StringRef getRelocationTypeName(uint16_t Type) const;
 
 protected:

diff  --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index 1b7ab45ea8aacc..08eb0d034c53a3 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -753,6 +753,54 @@ Error COFFObjectFile::initLoadConfigPtr() {
     return E;
 
   LoadConfig = (const void *)IntPtr;
+
+  if (is64()) {
+    auto Config = getLoadConfig64();
+    if (Config->Size >=
+            offsetof(coff_load_configuration64, CHPEMetadataPointer) +
+                sizeof(Config->CHPEMetadataPointer) &&
+        Config->CHPEMetadataPointer) {
+      uint64_t ChpeOff = Config->CHPEMetadataPointer;
+      if (Error E =
+              getRvaPtr(ChpeOff - getImageBase(), IntPtr, "CHPE metadata"))
+        return E;
+      if (Error E = checkOffset(Data, IntPtr, sizeof(CHPEMetadata)))
+        return E;
+
+      CHPEMetadata = reinterpret_cast<const chpe_metadata *>(IntPtr);
+
+      // Validate CHPE metadata
+      if (CHPEMetadata->CodeMapCount) {
+        if (Error E = getRvaPtr(CHPEMetadata->CodeMap, IntPtr, "CHPE code map"))
+          return E;
+        if (Error E = checkOffset(Data, IntPtr,
+                                  CHPEMetadata->CodeMapCount *
+                                      sizeof(chpe_range_entry)))
+          return E;
+      }
+
+      if (CHPEMetadata->CodeRangesToEntryPointsCount) {
+        if (Error E = getRvaPtr(CHPEMetadata->CodeRangesToEntryPoints, IntPtr,
+                                "CHPE entry point ranges"))
+          return E;
+        if (Error E = checkOffset(Data, IntPtr,
+                                  CHPEMetadata->CodeRangesToEntryPointsCount *
+                                      sizeof(chpe_code_range_entry)))
+          return E;
+      }
+
+      if (CHPEMetadata->RedirectionMetadataCount) {
+        if (Error E = getRvaPtr(CHPEMetadata->RedirectionMetadata, IntPtr,
+                                "CHPE redirection metadata"))
+          return E;
+        if (Error E = checkOffset(Data, IntPtr,
+                                  CHPEMetadata->RedirectionMetadataCount *
+                                      sizeof(chpe_redirection_entry)))
+          return E;
+      }
+    }
+  }
+
   return Error::success();
 }
 

diff  --git a/llvm/test/tools/llvm-readobj/arm64ec-chpe.yaml b/llvm/test/tools/llvm-readobj/arm64ec-chpe.yaml
new file mode 100644
index 00000000000000..629fe027b64e33
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/arm64ec-chpe.yaml
@@ -0,0 +1,49 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-readobj --coff-load-config %t | FileCheck %s
+
+# CHECK: CHPEMetadataPointer: 0x180005000
+# CHECK:      CHPEMetadata [
+# CHECK-NEXT:   Version: 0x1
+# CHECK-NEXT:   CodeMap [
+# CHECK-NEXT:     0x1000 - 0x1030  ARM64EC
+# CHECK-NEXT:     0x2000 - 0x2040  ARM64
+# CHECK-NEXT:     0x3000 - 0x3050  X64
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   CodeRangesToEntryPoints [
+# CHECK-NEXT:     0x1000 - 0x1020 -> 0x1000
+# CHECK-NEXT:     0x1020 - 0x1040 -> 0x2000
+# CHECK-NEXT:   ]
+# CHECK-NEXT:   RedirectionMetadata [
+# CHECK-NEXT:     0x1000 -> 0x2000
+# CHECK-NEXT:     0x1020 -> 0x2030
+# CHECK-NEXT:   ]
+
+--- !COFF
+OptionalHeader:
+  ImageBase:       0x180000000
+  SectionAlignment: 4096
+  FileAlignment:   512
+  DLLCharacteristics: [ ]
+  LoadConfigTable:
+    RelativeVirtualAddress: 0x4000
+    Size:            320
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE, IMAGE_FILE_DLL ]
+sections:
+  - Name:            .text
+    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  0x1000
+    VirtualSize:     0x2050
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  0x4000
+    VirtualSize:     328
+    SectionData:     '40010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000050008001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
+  - Name:            .data
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
+    VirtualAddress:  0x5000
+    VirtualSize:     144
+    SectionData:     '010000005050000003000000685000008050000000000000000000000000000000000000000000000000000000000000020000000200000000000000000000000000000000000000000000000000000001100000300000000020000040000000023000005000000000100000201000000010000020100000401000000020000000100000002000002010000030200000'
+symbols:         []
+...

diff  --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index c6d1f2cf9c63d0..0a5073d2d23fa0 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -842,6 +842,93 @@ void COFFDumper::printCOFFLoadConfig() {
   else
     printCOFFLoadConfig(Obj->getLoadConfig32(), Tables);
 
+  if (auto CHPE = Obj->getCHPEMetadata()) {
+    ListScope LS(W, "CHPEMetadata");
+    W.printHex("Version", CHPE->Version);
+
+    if (CHPE->CodeMapCount) {
+      ListScope CMLS(W, "CodeMap");
+
+      uintptr_t CodeMapInt;
+      if (Error E = Obj->getRvaPtr(CHPE->CodeMap, CodeMapInt))
+        reportError(std::move(E), Obj->getFileName());
+      auto CodeMap = reinterpret_cast<const chpe_range_entry *>(CodeMapInt);
+      for (uint32_t i = 0; i < CHPE->CodeMapCount; i++) {
+        uint32_t Start = CodeMap[i].StartOffset & ~3;
+        W.startLine() << W.hex(Start) << " - "
+                      << W.hex(Start + CodeMap[i].Length) << "  ";
+        switch (CodeMap[i].StartOffset & 3) {
+        case CHPE_RANGE_ARM64:
+          W.getOStream() << "ARM64\n";
+          break;
+        case CHPE_RANGE_ARM64EC:
+          W.getOStream() << "ARM64EC\n";
+          break;
+        case CHPE_RANGE_AMD64:
+          W.getOStream() << "X64\n";
+          break;
+        default:
+          W.getOStream() << W.hex(CodeMap[i].StartOffset & 3) << "\n";
+          break;
+        }
+      }
+    } else {
+      W.printNumber("CodeMap", CHPE->CodeMap);
+    }
+
+    if (CHPE->CodeRangesToEntryPointsCount) {
+      ListScope CRLS(W, "CodeRangesToEntryPoints");
+
+      uintptr_t CodeRangesInt;
+      if (Error E =
+              Obj->getRvaPtr(CHPE->CodeRangesToEntryPoints, CodeRangesInt))
+        reportError(std::move(E), Obj->getFileName());
+      auto CodeRanges =
+          reinterpret_cast<const chpe_code_range_entry *>(CodeRangesInt);
+      for (uint32_t i = 0; i < CHPE->CodeRangesToEntryPointsCount; i++) {
+        W.startLine() << W.hex(CodeRanges[i].StartRva) << " - "
+                      << W.hex(CodeRanges[i].EndRva) << " -> "
+                      << W.hex(CodeRanges[i].EntryPoint) << "\n";
+      }
+    } else {
+      W.printNumber("CodeRangesToEntryPoints", CHPE->CodeRangesToEntryPoints);
+    }
+
+    if (CHPE->RedirectionMetadataCount) {
+      ListScope RMLS(W, "RedirectionMetadata");
+
+      uintptr_t RedirMetadataInt;
+      if (Error E = Obj->getRvaPtr(CHPE->RedirectionMetadata, RedirMetadataInt))
+        reportError(std::move(E), Obj->getFileName());
+      auto RedirMetadata =
+          reinterpret_cast<const chpe_redirection_entry *>(RedirMetadataInt);
+      for (uint32_t i = 0; i < CHPE->RedirectionMetadataCount; i++) {
+        W.startLine() << W.hex(RedirMetadata[i].Source) << " -> "
+                      << W.hex(RedirMetadata[i].Destination) << "\n";
+      }
+    } else {
+      W.printNumber("RedirectionMetadata", CHPE->RedirectionMetadata);
+    }
+
+    W.printHex("__os_arm64x_dispatch_call_no_redirect",
+               CHPE->__os_arm64x_dispatch_call_no_redirect);
+    W.printHex("__os_arm64x_dispatch_ret", CHPE->__os_arm64x_dispatch_ret);
+    W.printHex("__os_arm64x_dispatch_call", CHPE->__os_arm64x_dispatch_call);
+    W.printHex("__os_arm64x_dispatch_icall", CHPE->__os_arm64x_dispatch_icall);
+    W.printHex("__os_arm64x_dispatch_icall_cfg",
+               CHPE->__os_arm64x_dispatch_icall_cfg);
+    W.printHex("AlternateEntryPoint", CHPE->AlternateEntryPoint);
+    W.printHex("AuxiliaryIAT", CHPE->AuxiliaryIAT);
+    W.printHex("GetX64InformationFunctionPointer",
+               CHPE->GetX64InformationFunctionPointer);
+    W.printHex("SetX64InformationFunctionPointer",
+               CHPE->SetX64InformationFunctionPointer);
+    W.printHex("ExtraRFETable", CHPE->ExtraRFETable);
+    W.printHex("ExtraRFETableSize", CHPE->ExtraRFETableSize);
+    W.printHex("__os_arm64x_dispatch_fptr", CHPE->__os_arm64x_dispatch_fptr);
+    W.printHex("AuxiliaryIATCopy", CHPE->AuxiliaryIATCopy);
+  }
+
   if (Tables.SEHTableVA) {
     ListScope LS(W, "SEHTable");
     printRVATable(Tables.SEHTableVA, Tables.SEHTableCount, 4);
@@ -921,7 +1008,7 @@ void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) {
   W.printHex("SecurityCookie", Conf->SecurityCookie);
 
   // Print the safe SEH table if present.
-  if (Conf->Size < offsetof(coff_load_configuration32, GuardCFCheckFunction))
+  if (Conf->Size < offsetof(T, GuardCFCheckFunction))
     return;
   W.printHex("SEHandlerTable", Conf->SEHandlerTable);
   W.printNumber("SEHandlerCount", Conf->SEHandlerCount);


        


More information about the llvm-commits mailing list