/// 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
/// +---------------------------------------------------------------+
/// 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:
--- /dev/null
+## 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
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) {
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);
}