Index: llvm/include/llvm/Support/ARMWinEH.h =================================================================== --- llvm/include/llvm/Support/ARMWinEH.h +++ llvm/include/llvm/Support/ARMWinEH.h @@ -31,6 +31,9 @@ /// 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 @@ /// purpose (r0-r15) and VFP (d0-d31) registers. std::pair 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: Index: llvm/test/tools/llvm-readobj/COFF/arm64-packed-unwind.s =================================================================== --- /dev/null +++ llvm/test/tools/llvm-readobj/COFF/arm64-packed-unwind.s @@ -0,0 +1,313 @@ +## Check interpretation of the packed unwind info format. + +// REQUIRES: aarch64-registered-target +// RUN: llvm-mc -filetype=obj -triple aarch64-windows %s -o - \ +// RUN: | llvm-readobj --unwind - | 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: sub sp, sp, #0 +// 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: sub sp, sp, #0 +// 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: sub sp, sp, #0 +// 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: ] + + .text + .globl func1 +func1: +func2: +func3: +func4: +func5: +func6: +func7: +func8: +func9: +func10: +func11: +func12: +func13: +func14: +func15: + 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 Index: llvm/tools/llvm-readobj/ARMWinEHPrinter.h =================================================================== --- llvm/tools/llvm-readobj/ARMWinEHPrinter.h +++ llvm/tools/llvm-readobj/ARMWinEHPrinter.h @@ -17,6 +17,7 @@ namespace ARM { namespace WinEH { class RuntimeFunction; +class RuntimeFunctionARM64; class Decoder { static const size_t PDataEntrySize; @@ -154,6 +155,9 @@ 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 Contents); Index: llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp =================================================================== --- llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -1111,6 +1111,135 @@ 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 Function = getRelocatedSymbol(COFF, Section, Offset); + if (!Function) + Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); + + StringRef FunctionName; + uint64_t FunctionAddress; + if (Function) { + Expected 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 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"); + + 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 > 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() + RF.RegF() > 0) + SW.startLine() << format("stp x0, x1, [sp, #%d]\n", IntSZ + FpSZ); + else // This case isn't documented + 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 Contents) { @@ -1123,8 +1252,8 @@ 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); }