[llvm-readobj] [ARMWinEH] Print ARM64 packed unwind info
authorMartin Storsjö <martin@martin.st>
Fri, 4 Sep 2020 20:42:22 +0000 (23:42 +0300)
committerMartin Storsjö <martin@martin.st>
Tue, 15 Sep 2020 05:50:02 +0000 (08:50 +0300)
In addition to printing the individual fields, synthesize and
print the corresponding prolog for the unwind info (in reverse
order, to match how it's printed for non-packed unwind info).

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

llvm/include/llvm/Support/ARMWinEH.h
llvm/test/tools/llvm-readobj/COFF/arm64-packed-unwind.s [new file with mode: 0644]
llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp
llvm/tools/llvm-readobj/ARMWinEHPrinter.h

index 83ba044..327aa98 100644 (file)
@@ -31,6 +31,9 @@ enum class ReturnType {
 
 /// RuntimeFunction - An entry in the table of procedure data (.pdata)
 ///
+/// This is ARM specific, but the Function Start RVA, Flag and
+/// ExceptionInformationRVA fields work identically for ARM64.
+///
 ///  3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
 ///  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
 /// +---------------------------------------------------------------+
@@ -204,6 +207,85 @@ inline uint16_t StackAdjustment(const RuntimeFunction &RF) {
 /// purpose (r0-r15) and VFP (d0-d31) registers.
 std::pair<uint16_t, uint32_t> SavedRegisterMask(const RuntimeFunction &RF);
 
+/// RuntimeFunctionARM64 - An entry in the table of procedure data (.pdata)
+///
+///  3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
+///  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+/// +---------------------------------------------------------------+
+/// |                     Function Start RVA                        |
+/// +-----------------+---+-+-------+-----+---------------------+---+
+/// |    Frame Size   |CR |H| RegI  |RegF |   Function Length   |Flg|
+/// +-----------------+---+-+-------+-----+---------------------+---+
+///
+/// See https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
+/// for the full reference for this struct.
+
+class RuntimeFunctionARM64 {
+public:
+  const support::ulittle32_t BeginAddress;
+  const support::ulittle32_t UnwindData;
+
+  RuntimeFunctionARM64(const support::ulittle32_t *Data)
+      : BeginAddress(Data[0]), UnwindData(Data[1]) {}
+
+  RuntimeFunctionARM64(const support::ulittle32_t BeginAddress,
+                       const support::ulittle32_t UnwindData)
+      : BeginAddress(BeginAddress), UnwindData(UnwindData) {}
+
+  RuntimeFunctionFlag Flag() const {
+    return RuntimeFunctionFlag(UnwindData & 0x3);
+  }
+
+  uint32_t ExceptionInformationRVA() const {
+    assert(Flag() == RuntimeFunctionFlag::RFF_Unpacked &&
+           "unpacked form required for this operation");
+    return (UnwindData & ~0x3);
+  }
+
+  uint32_t PackedUnwindData() const {
+    assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+            Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+           "packed form required for this operation");
+    return (UnwindData & ~0x3);
+  }
+  uint32_t FunctionLength() const {
+    assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+            Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+           "packed form required for this operation");
+    return (((UnwindData & 0x00001ffc) >> 2) << 2);
+  }
+  uint8_t RegF() const {
+    assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+            Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+           "packed form required for this operation");
+    return ((UnwindData & 0x0000e000) >> 13);
+  }
+  uint8_t RegI() const {
+    assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+            Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+           "packed form required for this operation");
+    return ((UnwindData & 0x000f0000) >> 16);
+  }
+  bool H() const {
+    assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+            Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+           "packed form required for this operation");
+    return ((UnwindData & 0x00100000) >> 20);
+  }
+  uint8_t CR() const {
+    assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+            Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+           "packed form required for this operation");
+    return ((UnwindData & 0x600000) >> 21);
+  }
+  uint16_t FrameSize() const {
+    assert((Flag() == RuntimeFunctionFlag::RFF_Packed ||
+            Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+           "packed form required for this operation");
+    return ((UnwindData & 0xff800000) >> 23);
+  }
+};
+
 /// ExceptionDataRecord - An entry in the table of exception data (.xdata)
 ///
 /// The format on ARM is:
diff --git a/llvm/test/tools/llvm-readobj/COFF/arm64-packed-unwind.s b/llvm/test/tools/llvm-readobj/COFF/arm64-packed-unwind.s
new file mode 100644 (file)
index 0000000..f8c4d5e
--- /dev/null
@@ -0,0 +1,332 @@
+## Check interpretation of the packed unwind info format.
+
+// REQUIRES: aarch64-registered-target
+// RUN: llvm-mc -filetype=obj -triple aarch64-windows %s -o %t.o
+// RUN: llvm-readobj --unwind %t.o | FileCheck %s
+
+// CHECK:      UnwindInformation [
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func1
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 88
+// CHECK-NEXT:     RegF: 7
+// CHECK-NEXT:     RegI: 10
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 160
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       stp d14, d15, [sp, #128]
+// CHECK-NEXT:       stp d12, d13, [sp, #112]
+// CHECK-NEXT:       stp d10, d11, [sp, #96]
+// CHECK-NEXT:       stp d8, d9, [sp, #80]
+// CHECK-NEXT:       stp x27, x28, [sp, #64]
+// CHECK-NEXT:       stp x25, x26, [sp, #48]
+// CHECK-NEXT:       stp x23, x24, [sp, #32]
+// CHECK-NEXT:       stp x21, x22, [sp, #16]
+// CHECK-NEXT:       stp x19, x20, [sp, #-144]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func2
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 48
+// CHECK-NEXT:     RegF: 2
+// CHECK-NEXT:     RegI: 3
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 48
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       str d10, [sp, #40]
+// CHECK-NEXT:       stp d8, d9, [sp, #24]
+// CHECK-NEXT:       str x21, [sp, #16]
+// CHECK-NEXT:       stp x19, x20, [sp, #-48]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func3
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 40
+// CHECK-NEXT:     RegF: 3
+// CHECK-NEXT:     RegI: 1
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 48
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       stp d10, d11, [sp, #24]
+// CHECK-NEXT:       stp d8, d9, [sp, #8]
+// CHECK-NEXT:       str x19, [sp, #-48]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func4
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 24
+// CHECK-NEXT:     RegF: 1
+// CHECK-NEXT:     RegI: 0
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 48
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #32
+// CHECK-NEXT:       stp d8, d9, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func5
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 56
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 1
+// CHECK-NEXT:     HomedParameters: Yes
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 112
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #32
+// CHECK-NEXT:       stp x6, x7, [sp, #56]
+// CHECK-NEXT:       stp x4, x5, [sp, #40]
+// CHECK-NEXT:       stp x2, x3, [sp, #24]
+// CHECK-NEXT:       stp x0, x1, [sp, #8]
+// CHECK-NEXT:       str x19, [sp, #-80]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func6
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 48
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 0
+// CHECK-NEXT:     HomedParameters: Yes
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 112
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #48
+// CHECK-NEXT:       stp x6, x7, [sp, #48]
+// CHECK-NEXT:       stp x4, x5, [sp, #32]
+// CHECK-NEXT:       stp x2, x3, [sp, #16]
+// CHECK-NEXT:       stp x0, x1, [sp, #-64]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func7
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 24
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 0
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 1
+// CHECK-NEXT:     FrameSize: 32
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       str lr, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func8
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 24
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 1
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 1
+// CHECK-NEXT:     FrameSize: 32
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       stp x19, lr, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func9
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 32
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 1
+// CHECK-NEXT:     FrameSize: 32
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       str lr, [sp, #16]
+// CHECK-NEXT:       stp x19, x20, [sp, #-32]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func10
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 32
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 3
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 1
+// CHECK-NEXT:     FrameSize: 48
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       stp x21, lr, [sp, #16]
+// CHECK-NEXT:       stp x19, x20, [sp, #-32]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func11
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 32
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 3
+// CHECK-NEXT:     FrameSize: 48
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       mov x29, sp
+// CHECK-NEXT:       stp x29, lr, [sp, #-32]!
+// CHECK-NEXT:       stp x19, x20, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func12
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 40
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 3
+// CHECK-NEXT:     FrameSize: 544
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       mov x29, sp
+// CHECK-NEXT:       stp x29, lr, [sp, #0]
+// CHECK-NEXT:       sub sp, sp, #528
+// CHECK-NEXT:       stp x19, x20, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func13
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 48
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 3
+// CHECK-NEXT:     FrameSize: 4112
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       mov x29, sp
+// CHECK-NEXT:       stp x29, lr, [sp, #0]
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       sub sp, sp, #4080
+// CHECK-NEXT:       stp x19, x20, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func14
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 32
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 4112
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #16
+// CHECK-NEXT:       sub sp, sp, #4080
+// CHECK-NEXT:       stp x19, x20, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func15
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 24
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 2
+// CHECK-NEXT:     HomedParameters: No
+// CHECK-NEXT:     CR: 0
+// CHECK-NEXT:     FrameSize: 560
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #544
+// CHECK-NEXT:       stp x19, x20, [sp, #-16]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT:   RuntimeFunction {
+// CHECK-NEXT:     Function: func16
+// CHECK-NEXT:     Fragment: No
+// CHECK-NEXT:     FunctionLength: 56
+// CHECK-NEXT:     RegF: 0
+// CHECK-NEXT:     RegI: 0
+// CHECK-NEXT:     HomedParameters: Yes
+// CHECK-NEXT:     CR: 1
+// CHECK-NEXT:     FrameSize: 112
+// CHECK-NEXT:     Prologue [
+// CHECK-NEXT:       sub sp, sp, #32
+// CHECK-NEXT:       stp x6, x7, [sp, #56]
+// CHECK-NEXT:       stp x4, x5, [sp, #40]
+// CHECK-NEXT:       stp x2, x3, [sp, #24]
+// CHECK-NEXT:       stp x0, x1, [sp, #8]
+// CHECK-NEXT:       str lr, [sp, #-80]!
+// CHECK-NEXT:       end
+// CHECK-NEXT:     ]
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+        .text
+        .globl func1
+func1:
+func2:
+func3:
+func4:
+func5:
+func6:
+func7:
+func8:
+func9:
+func10:
+func11:
+func12:
+func13:
+func14:
+func15:
+func16:
+        ret
+
+        .section .pdata,"dr"
+        .long func1@IMGREL
+        .long 0x050ae059 // FunctionLength=22 RegF=7 RegI=10 H=0 CR=0 FrameSize=10
+        .long func2@IMGREL
+        .long 0x01834031 // FunctionLength=12 RegF=2 RegI=3 H=0 CR=0 FrameSize=3
+        .long func3@IMGREL
+        .long 0x01816029 // FunctionLength=10 RegF=3 RegI=1 H=0 CR=0 FrameSize=3
+        .long func4@IMGREL
+        .long 0x01802019 // FunctionLength=6  RegF=1 RegI=0 H=0 CR=0 FrameSize=3
+        .long func5@IMGREL
+        .long 0x03910039 // FunctionLength=14 RegF=0 RegI=1 H=1 CR=0 FrameSize=7
+        .long func6@IMGREL
+        .long 0x03900031 // FunctionLength=12 RegF=0 RegI=0 H=1 CR=0 FrameSize=7
+        .long func7@IMGREL
+        .long 0x01200019 // FunctionLength=6  RegF=0 RegI=0 H=0 CR=1 FrameSize=2
+        .long func8@IMGREL
+        .long 0x01210019 // FunctionLength=6  RegF=0 RegI=1 H=0 CR=1 FrameSize=2
+        .long func9@IMGREL
+        .long 0x01220021 // FunctionLength=8  RegF=0 RegI=2 H=0 CR=1 FrameSize=2
+        .long func10@IMGREL
+        .long 0x01a30021 // FunctionLength=8  RegF=0 RegI=3 H=0 CR=1 FrameSize=3
+        .long func11@IMGREL
+        .long 0x01e20021 // FunctionLength=8  RegF=0 RegI=2 H=0 CR=3 FrameSize=3
+        .long func12@IMGREL
+        .long 0x11620029 // FunctionLength=10 RegF=0 RegI=2 H=0 CR=3 FrameSize=34
+        .long func13@IMGREL
+        .long 0x80e20031 // FunctionLength=12 RegF=0 RegI=2 H=0 CR=3 FrameSize=257
+        .long func14@IMGREL
+        .long 0x80820021 // FunctionLength=8  RegF=0 RegI=2 H=0 CR=0 FrameSize=257
+        .long func15@IMGREL
+        .long 0x11820019 // FunctionLength=6  RegF=0 RegI=2 H=0 CR=0 FrameSize=34
+        .long func16@IMGREL
+        .long 0x03b00039 // FunctionLength=14 RegF=0 RegI=0 H=1 CR=1 FrameSize=7
index c2a84e3..46a949b 100644 (file)
@@ -1111,6 +1111,143 @@ bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF,
   return true;
 }
 
+bool Decoder::dumpPackedARM64Entry(const object::COFFObjectFile &COFF,
+                                   const SectionRef Section, uint64_t Offset,
+                                   unsigned Index,
+                                   const RuntimeFunctionARM64 &RF) {
+  assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed ||
+          RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) &&
+         "unpacked entry cannot be treated as a packed entry");
+
+  ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset);
+  if (!Function)
+    Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true);
+
+  StringRef FunctionName;
+  uint64_t FunctionAddress;
+  if (Function) {
+    Expected<StringRef> FunctionNameOrErr = Function->getName();
+    if (!FunctionNameOrErr) {
+      std::string Buf;
+      llvm::raw_string_ostream OS(Buf);
+      logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS);
+      OS.flush();
+      report_fatal_error(Buf);
+    }
+    FunctionName = *FunctionNameOrErr;
+    Expected<uint64_t> FunctionAddressOrErr = Function->getAddress();
+    if (!FunctionAddressOrErr) {
+      std::string Buf;
+      llvm::raw_string_ostream OS(Buf);
+      logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS);
+      OS.flush();
+      report_fatal_error(Buf);
+    }
+    FunctionAddress = *FunctionAddressOrErr;
+  } else {
+    FunctionAddress = COFF.getPE32PlusHeader()->ImageBase + RF.BeginAddress;
+  }
+
+  SW.printString("Function", formatSymbol(FunctionName, FunctionAddress));
+  SW.printBoolean("Fragment",
+                  RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment);
+  SW.printNumber("FunctionLength", RF.FunctionLength());
+  SW.printNumber("RegF", RF.RegF());
+  SW.printNumber("RegI", RF.RegI());
+  SW.printBoolean("HomedParameters", RF.H());
+  SW.printNumber("CR", RF.CR());
+  SW.printNumber("FrameSize", RF.FrameSize() << 4);
+  ListScope PS(SW, "Prologue");
+
+  // Synthesize the equivalent prologue according to the documentation
+  // at https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling,
+  // printed in reverse order compared to the docs, to match how prologues
+  // are printed for the non-packed case.
+  int IntSZ = 8 * RF.RegI();
+  if (RF.CR() == 1)
+    IntSZ += 8;
+  int FpSZ = 8 * RF.RegF();
+  if (RF.RegF())
+    FpSZ += 8;
+  int SavSZ = (IntSZ + FpSZ + 8 * 8 * RF.H() + 0xf) & ~0xf;
+  int LocSZ = (RF.FrameSize() << 4) - SavSZ;
+
+  if (RF.CR() == 3) {
+    SW.startLine() << "mov x29, sp\n";
+    if (LocSZ <= 512) {
+      SW.startLine() << format("stp x29, lr, [sp, #-%d]!\n", LocSZ);
+    } else {
+      SW.startLine() << "stp x29, lr, [sp, #0]\n";
+    }
+  }
+  if (LocSZ > 4080) {
+    SW.startLine() << format("sub sp, sp, #%d\n", LocSZ - 4080);
+    SW.startLine() << "sub sp, sp, #4080\n";
+  } else if ((RF.CR() != 3 && LocSZ > 0) || LocSZ > 512) {
+    SW.startLine() << format("sub sp, sp, #%d\n", LocSZ);
+  }
+  if (RF.H()) {
+    SW.startLine() << format("stp x6, x7, [sp, #%d]\n", IntSZ + FpSZ + 48);
+    SW.startLine() << format("stp x4, x5, [sp, #%d]\n", IntSZ + FpSZ + 32);
+    SW.startLine() << format("stp x2, x3, [sp, #%d]\n", IntSZ + FpSZ + 16);
+    if (RF.RegI() > 0 || RF.RegF() > 0 || RF.CR() == 1) {
+      SW.startLine() << format("stp x0, x1, [sp, #%d]\n", IntSZ + FpSZ);
+    } else {
+      // This case isn't documented; if neither RegI nor RegF nor CR=1
+      // have decremented the stack pointer by SavSZ, we need to do it here
+      // (as the final stack adjustment of LocSZ excludes SavSZ).
+      SW.startLine() << format("stp x0, x1, [sp, #-%d]!\n", SavSZ);
+    }
+  }
+  int FloatRegs = RF.RegF() > 0 ? RF.RegF() + 1 : 0;
+  for (int I = (FloatRegs + 1) / 2 - 1; I >= 0; I--) {
+    if (I == (FloatRegs + 1) / 2 - 1 && FloatRegs % 2 == 1) {
+      // The last register, an odd register without a pair
+      SW.startLine() << format("str d%d, [sp, #%d]\n", 8 + 2 * I,
+                               IntSZ + 16 * I);
+    } else if (I == 0 && RF.RegI() == 0 && RF.CR() != 1) {
+      SW.startLine() << format("stp d%d, d%d, [sp, #-%d]!\n", 8 + 2 * I,
+                               8 + 2 * I + 1, SavSZ);
+    } else {
+      SW.startLine() << format("stp d%d, d%d, [sp, #%d]\n", 8 + 2 * I,
+                               8 + 2 * I + 1, IntSZ + 16 * I);
+    }
+  }
+  if (RF.CR() == 1 && (RF.RegI() % 2) == 0) {
+    if (RF.RegI() == 0)
+      SW.startLine() << format("str lr, [sp, #-%d]!\n", SavSZ);
+    else
+      SW.startLine() << format("str lr, [sp, #%d]\n", IntSZ - 8);
+  }
+  for (int I = (RF.RegI() + 1) / 2 - 1; I >= 0; I--) {
+    if (I == (RF.RegI() + 1) / 2 - 1 && RF.RegI() % 2 == 1) {
+      // The last register, an odd register without a pair
+      if (RF.CR() == 1) {
+        if (I == 0) // If this is the only register pair
+          SW.startLine() << format("stp x%d, lr, [sp, #-%d]!\n", 19 + 2 * I,
+                                   SavSZ);
+        else
+          SW.startLine() << format("stp x%d, lr, [sp, #%d]\n", 19 + 2 * I,
+                                   16 * I);
+      } else {
+        if (I == 0)
+          SW.startLine() << format("str x%d, [sp, #-%d]!\n", 19 + 2 * I, SavSZ);
+        else
+          SW.startLine() << format("str x%d, [sp, #%d]\n", 19 + 2 * I, 16 * I);
+      }
+    } else if (I == 0) {
+      // The first register pair
+      SW.startLine() << format("stp x19, x20, [sp, #-%d]!\n", SavSZ);
+    } else {
+      SW.startLine() << format("stp x%d, x%d, [sp, #%d]\n", 19 + 2 * I,
+                               19 + 2 * I + 1, 16 * I);
+    }
+  }
+  SW.startLine() << "end\n";
+
+  return true;
+}
+
 bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF,
                                      const SectionRef Section, unsigned Index,
                                      ArrayRef<uint8_t> Contents) {
@@ -1123,8 +1260,8 @@ bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF,
   if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked)
     return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry);
   if (isAArch64) {
-    SW.startLine() << "Packed unwind data not yet supported for ARM64\n";
-    return true;
+    const RuntimeFunctionARM64 EntryARM64(Data);
+    return dumpPackedARM64Entry(COFF, Section, Offset, Index, EntryARM64);
   }
   return dumpPackedEntry(COFF, Section, Offset, Index, Entry);
 }
index 36fe5d6..3263841 100644 (file)
@@ -17,6 +17,7 @@ namespace llvm {
 namespace ARM {
 namespace WinEH {
 class RuntimeFunction;
+class RuntimeFunctionARM64;
 
 class Decoder {
   static const size_t PDataEntrySize;
@@ -154,6 +155,9 @@ class Decoder {
   bool dumpPackedEntry(const object::COFFObjectFile &COFF,
                        const object::SectionRef Section, uint64_t Offset,
                        unsigned Index, const RuntimeFunction &Entry);
+  bool dumpPackedARM64Entry(const object::COFFObjectFile &COFF,
+                            const object::SectionRef Section, uint64_t Offset,
+                            unsigned Index, const RuntimeFunctionARM64 &Entry);
   bool dumpProcedureDataEntry(const object::COFFObjectFile &COFF,
                               const object::SectionRef Section, unsigned Entry,
                               ArrayRef<uint8_t> Contents);