diff --git a/llvm/include/llvm/Support/Win64EH.h b/llvm/include/llvm/Support/Win64EH.h --- a/llvm/include/llvm/Support/Win64EH.h +++ b/llvm/include/llvm/Support/Win64EH.h @@ -38,12 +38,14 @@ // The following set of unwind opcodes is for ARM64. They are documented at // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling UOP_AllocMedium, + UOP_SaveR19R20X, UOP_SaveFPLRX, UOP_SaveFPLR, UOP_SaveReg, UOP_SaveRegX, UOP_SaveRegP, UOP_SaveRegPX, + UOP_SaveLRPair, UOP_SaveFReg, UOP_SaveFRegX, UOP_SaveFRegP, @@ -51,7 +53,11 @@ UOP_SetFP, UOP_AddFP, UOP_Nop, - UOP_End + UOP_End, + UOP_SaveNext, + UOP_TrapFrame, + UOP_Context, + UOP_ClearUnwoundToCall }; /// UnwindCode - This union describes a single operation in a function prolog, diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp --- a/llvm/lib/MC/MCWin64EH.cpp +++ b/llvm/lib/MC/MCWin64EH.cpp @@ -280,6 +280,9 @@ case Win64EH::UOP_AllocLarge: Count += 4; break; + case Win64EH::UOP_SaveR19R20X: + Count += 1; + break; case Win64EH::UOP_SaveFPLRX: Count += 1; break; @@ -298,6 +301,9 @@ case Win64EH::UOP_SaveRegX: Count += 2; break; + case Win64EH::UOP_SaveLRPair: + Count += 2; + break; case Win64EH::UOP_SaveFReg: Count += 2; break; @@ -322,6 +328,21 @@ case Win64EH::UOP_End: Count += 1; break; + case Win64EH::UOP_SaveNext: + Count += 1; + break; + case Win64EH::UOP_TrapFrame: + Count += 1; + break; + case Win64EH::UOP_PushMachFrame: + Count += 1; + break; + case Win64EH::UOP_Context: + Count += 1; + break; + case Win64EH::UOP_ClearUnwoundToCall: + Count += 1; + break; } } return Count; @@ -375,6 +396,11 @@ b = 0xE3; streamer.emitInt8(b); break; + case Win64EH::UOP_SaveR19R20X: + b = 0x20; + b |= (inst.Offset >> 3) & 0x1F; + streamer.emitInt8(b); + break; case Win64EH::UOP_SaveFPLRX: b = 0x80; b |= ((inst.Offset - 1) >> 3) & 0x3F; @@ -417,6 +443,16 @@ b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1); streamer.emitInt8(b); break; + case Win64EH::UOP_SaveLRPair: + assert(inst.Register >= 19 && "Saved reg must be >= 19"); + reg = inst.Register - 19; + assert((reg % 2) == 0 && "Saved reg must be 19+2*X"); + reg /= 2; + b = 0xD6 | ((reg & 0x7) >> 2); + streamer.emitInt8(b); + b = ((reg & 0x3) << 6) | (inst.Offset >> 3); + streamer.emitInt8(b); + break; case Win64EH::UOP_SaveFReg: assert(inst.Register >= 8 && "Saved dreg must be >= 8"); reg = inst.Register - 8; @@ -453,6 +489,26 @@ b = 0xE4; streamer.emitInt8(b); break; + case Win64EH::UOP_SaveNext: + b = 0xE6; + streamer.emitInt8(b); + break; + case Win64EH::UOP_TrapFrame: + b = 0xE8; + streamer.emitInt8(b); + break; + case Win64EH::UOP_PushMachFrame: + b = 0xE9; + streamer.emitInt8(b); + break; + case Win64EH::UOP_Context: + b = 0xEA; + streamer.emitInt8(b); + break; + case Win64EH::UOP_ClearUnwoundToCall: + b = 0xEC; + streamer.emitInt8(b); + break; } } diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -186,12 +186,14 @@ bool parseDirectiveSEHAllocStack(SMLoc L); bool parseDirectiveSEHPrologEnd(SMLoc L); + bool parseDirectiveSEHSaveR19R20X(SMLoc L); bool parseDirectiveSEHSaveFPLR(SMLoc L); bool parseDirectiveSEHSaveFPLRX(SMLoc L); bool parseDirectiveSEHSaveReg(SMLoc L); bool parseDirectiveSEHSaveRegX(SMLoc L); bool parseDirectiveSEHSaveRegP(SMLoc L); bool parseDirectiveSEHSaveRegPX(SMLoc L); + bool parseDirectiveSEHSaveLRPair(SMLoc L); bool parseDirectiveSEHSaveFReg(SMLoc L); bool parseDirectiveSEHSaveFRegX(SMLoc L); bool parseDirectiveSEHSaveFRegP(SMLoc L); @@ -199,8 +201,13 @@ bool parseDirectiveSEHSetFP(SMLoc L); bool parseDirectiveSEHAddFP(SMLoc L); bool parseDirectiveSEHNop(SMLoc L); + bool parseDirectiveSEHSaveNext(SMLoc L); bool parseDirectiveSEHEpilogStart(SMLoc L); bool parseDirectiveSEHEpilogEnd(SMLoc L); + bool parseDirectiveSEHTrapFrame(SMLoc L); + bool parseDirectiveSEHMachineFrame(SMLoc L); + bool parseDirectiveSEHContext(SMLoc L); + bool parseDirectiveSEHClearUnwoundToCall(SMLoc L); bool validateInstruction(MCInst &Inst, SMLoc &IDLoc, SmallVectorImpl &Loc); @@ -5174,6 +5181,8 @@ parseDirectiveSEHAllocStack(Loc); else if (IDVal == ".seh_endprologue") parseDirectiveSEHPrologEnd(Loc); + else if (IDVal == ".seh_save_r19r20_x") + parseDirectiveSEHSaveR19R20X(Loc); else if (IDVal == ".seh_save_fplr") parseDirectiveSEHSaveFPLR(Loc); else if (IDVal == ".seh_save_fplr_x") @@ -5186,6 +5195,8 @@ parseDirectiveSEHSaveRegP(Loc); else if (IDVal == ".seh_save_regp_x") parseDirectiveSEHSaveRegPX(Loc); + else if (IDVal == ".seh_save_lrpair") + parseDirectiveSEHSaveLRPair(Loc); else if (IDVal == ".seh_save_freg") parseDirectiveSEHSaveFReg(Loc); else if (IDVal == ".seh_save_freg_x") @@ -5200,10 +5211,20 @@ parseDirectiveSEHAddFP(Loc); else if (IDVal == ".seh_nop") parseDirectiveSEHNop(Loc); + else if (IDVal == ".seh_save_next") + parseDirectiveSEHSaveNext(Loc); else if (IDVal == ".seh_startepilogue") parseDirectiveSEHEpilogStart(Loc); else if (IDVal == ".seh_endepilogue") parseDirectiveSEHEpilogEnd(Loc); + else if (IDVal == ".seh_trap_frame") + parseDirectiveSEHTrapFrame(Loc); + else if (IDVal == ".seh_pushframe") + parseDirectiveSEHMachineFrame(Loc); + else if (IDVal == ".seh_context") + parseDirectiveSEHContext(Loc); + else if (IDVal == ".seh_clear_unwound_to_call") + parseDirectiveSEHClearUnwoundToCall(Loc); else return true; } else @@ -5645,6 +5666,16 @@ return false; } +/// parseDirectiveSEHSaveR19R20X +/// ::= .seh_save_r19r20_x +bool AArch64AsmParser::parseDirectiveSEHSaveR19R20X(SMLoc L) { + int64_t Offset; + if (parseImmExpr(Offset)) + return true; + getTargetStreamer().EmitARM64WinCFISaveR19R20X(Offset); + return false; +} + /// parseDirectiveSEHSaveFPLR /// ::= .seh_save_fplr bool AArch64AsmParser::parseDirectiveSEHSaveFPLR(SMLoc L) { @@ -5713,6 +5744,22 @@ return false; } +/// parseDirectiveSEHSaveLRPair +/// ::= .seh_save_lrpair +bool AArch64AsmParser::parseDirectiveSEHSaveLRPair(SMLoc L) { + unsigned Reg; + int64_t Offset; + L = getLoc(); + if (parseRegisterInRange(Reg, AArch64::X0, AArch64::X19, AArch64::LR) || + parseComma() || parseImmExpr(Offset)) + return true; + if (check(((Reg - 19) % 2 != 0), L, + "expected register with even offset from x19")) + return true; + getTargetStreamer().EmitARM64WinCFISaveLRPair(Reg, Offset); + return false; +} + /// parseDirectiveSEHSaveFReg /// ::= .seh_save_freg bool AArch64AsmParser::parseDirectiveSEHSaveFReg(SMLoc L) { @@ -5785,6 +5832,13 @@ return false; } +/// parseDirectiveSEHSaveNext +/// ::= .seh_save_next +bool AArch64AsmParser::parseDirectiveSEHSaveNext(SMLoc L) { + getTargetStreamer().EmitARM64WinCFISaveNext(); + return false; +} + /// parseDirectiveSEHEpilogStart /// ::= .seh_startepilogue bool AArch64AsmParser::parseDirectiveSEHEpilogStart(SMLoc L) { @@ -5799,6 +5853,34 @@ return false; } +/// parseDirectiveSEHTrapFrame +/// ::= .seh_trap_frame +bool AArch64AsmParser::parseDirectiveSEHTrapFrame(SMLoc L) { + getTargetStreamer().EmitARM64WinCFITrapFrame(); + return false; +} + +/// parseDirectiveSEHMachineFrame +/// ::= .seh_pushframe +bool AArch64AsmParser::parseDirectiveSEHMachineFrame(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIMachineFrame(); + return false; +} + +/// parseDirectiveSEHContext +/// ::= .seh_context +bool AArch64AsmParser::parseDirectiveSEHContext(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIContext(); + return false; +} + +/// parseDirectiveSEHClearUnwoundToCall +/// ::= .seh_clear_unwound_to_call +bool AArch64AsmParser::parseDirectiveSEHClearUnwoundToCall(SMLoc L) { + getTargetStreamer().EmitARM64WinCFIClearUnwoundToCall(); + return false; +} + bool AArch64AsmParser::classifySymbolRef(const MCExpr *Expr, AArch64MCExpr::VariantKind &ELFRefKind, diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp @@ -50,6 +50,9 @@ void EmitARM64WinCFIAllocStack(unsigned Size) override { OS << "\t.seh_stackalloc " << Size << "\n"; } + void EmitARM64WinCFISaveR19R20X(int Offset) override { + OS << "\t.seh_save_r19r20_x " << Offset << "\n"; + } void EmitARM64WinCFISaveFPLR(int Offset) override { OS << "\t.seh_save_fplr " << Offset << "\n"; } @@ -68,6 +71,9 @@ void EmitARM64WinCFISaveRegPX(unsigned Reg, int Offset) override { OS << "\t.seh_save_regp_x x" << Reg << ", " << Offset << "\n"; } + void EmitARM64WinCFISaveLRPair(unsigned Reg, int Offset) override { + OS << "\t.seh_save_lrpair x" << Reg << ", " << Offset << "\n"; + } void EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) override { OS << "\t.seh_save_freg d" << Reg << ", " << Offset << "\n"; } @@ -85,9 +91,16 @@ OS << "\t.seh_add_fp " << Size << "\n"; } void EmitARM64WinCFINop() override { OS << "\t.seh_nop\n"; } + void EmitARM64WinCFISaveNext() override { OS << "\t.seh_save_next\n"; } void EmitARM64WinCFIPrologEnd() override { OS << "\t.seh_endprologue\n"; } void EmitARM64WinCFIEpilogStart() override { OS << "\t.seh_startepilogue\n"; } void EmitARM64WinCFIEpilogEnd() override { OS << "\t.seh_endepilogue\n"; } + void EmitARM64WinCFITrapFrame() override { OS << "\t.seh_trap_frame\n"; } + void EmitARM64WinCFIMachineFrame() override { OS << "\t.seh_pushframe\n"; } + void EmitARM64WinCFIContext() override { OS << "\t.seh_context\n"; } + void EmitARM64WinCFIClearUnwoundToCall() override { + OS << "\t.seh_clear_unwound_to_call\n"; + } public: AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h @@ -37,12 +37,14 @@ virtual void emitInst(uint32_t Inst); virtual void EmitARM64WinCFIAllocStack(unsigned Size) {} + virtual void EmitARM64WinCFISaveR19R20X(int Offset) {} virtual void EmitARM64WinCFISaveFPLR(int Offset) {} virtual void EmitARM64WinCFISaveFPLRX(int Offset) {} virtual void EmitARM64WinCFISaveReg(unsigned Reg, int Offset) {} virtual void EmitARM64WinCFISaveRegX(unsigned Reg, int Offset) {} virtual void EmitARM64WinCFISaveRegP(unsigned Reg, int Offset) {} virtual void EmitARM64WinCFISaveRegPX(unsigned Reg, int Offset) {} + virtual void EmitARM64WinCFISaveLRPair(unsigned Reg, int Offset) {} virtual void EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) {} virtual void EmitARM64WinCFISaveFRegX(unsigned Reg, int Offset) {} virtual void EmitARM64WinCFISaveFRegP(unsigned Reg, int Offset) {} @@ -50,9 +52,14 @@ virtual void EmitARM64WinCFISetFP() {} virtual void EmitARM64WinCFIAddFP(unsigned Size) {} virtual void EmitARM64WinCFINop() {} + virtual void EmitARM64WinCFISaveNext() {} virtual void EmitARM64WinCFIPrologEnd() {} virtual void EmitARM64WinCFIEpilogStart() {} virtual void EmitARM64WinCFIEpilogEnd() {} + virtual void EmitARM64WinCFITrapFrame() {} + virtual void EmitARM64WinCFIMachineFrame() {} + virtual void EmitARM64WinCFIContext() {} + virtual void EmitARM64WinCFIClearUnwoundToCall() {} private: std::unique_ptr ConstantPools; @@ -82,12 +89,14 @@ // The unwind codes on ARM64 Windows are documented at // https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling void EmitARM64WinCFIAllocStack(unsigned Size) override; + void EmitARM64WinCFISaveR19R20X(int Offset) override; void EmitARM64WinCFISaveFPLR(int Offset) override; void EmitARM64WinCFISaveFPLRX(int Offset) override; void EmitARM64WinCFISaveReg(unsigned Reg, int Offset) override; void EmitARM64WinCFISaveRegX(unsigned Reg, int Offset) override; void EmitARM64WinCFISaveRegP(unsigned Reg, int Offset) override; void EmitARM64WinCFISaveRegPX(unsigned Reg, int Offset) override; + void EmitARM64WinCFISaveLRPair(unsigned Reg, int Offset) override; void EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) override; void EmitARM64WinCFISaveFRegX(unsigned Reg, int Offset) override; void EmitARM64WinCFISaveFRegP(unsigned Reg, int Offset) override; @@ -95,9 +104,15 @@ void EmitARM64WinCFISetFP() override; void EmitARM64WinCFIAddFP(unsigned Size) override; void EmitARM64WinCFINop() override; + void EmitARM64WinCFISaveNext() override; void EmitARM64WinCFIPrologEnd() override; void EmitARM64WinCFIEpilogStart() override; void EmitARM64WinCFIEpilogEnd() override; + void EmitARM64WinCFITrapFrame() override; + void EmitARM64WinCFIMachineFrame() override; + void EmitARM64WinCFIContext() override; + void EmitARM64WinCFIClearUnwoundToCall() override; + private: void EmitARM64WinUnwindCode(unsigned UnwindCode, int Reg, int Offset); }; diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFStreamer.cpp @@ -85,6 +85,10 @@ EmitARM64WinUnwindCode(Op, -1, Size); } +void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveR19R20X(int Offset) { + EmitARM64WinUnwindCode(Win64EH::UOP_SaveR19R20X, -1, Offset); +} + void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFPLR(int Offset) { EmitARM64WinUnwindCode(Win64EH::UOP_SaveFPLR, -1, Offset); } @@ -115,6 +119,11 @@ EmitARM64WinUnwindCode(Win64EH::UOP_SaveRegPX, Reg, Offset); } +void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveLRPair(unsigned Reg, + int Offset) { + EmitARM64WinUnwindCode(Win64EH::UOP_SaveLRPair, Reg, Offset); +} + void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) { assert(Offset >= 0 && Offset <= 504 && @@ -150,6 +159,10 @@ EmitARM64WinUnwindCode(Win64EH::UOP_Nop, -1, 0); } +void AArch64TargetWinCOFFStreamer::EmitARM64WinCFISaveNext() { + EmitARM64WinUnwindCode(Win64EH::UOP_SaveNext, -1, 0); +} + // The functions below handle opcodes that can end up in either a prolog or // an epilog, but not both. void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIPrologEnd() { @@ -188,6 +201,22 @@ CurrentEpilog = nullptr; } +void AArch64TargetWinCOFFStreamer::EmitARM64WinCFITrapFrame() { + EmitARM64WinUnwindCode(Win64EH::UOP_TrapFrame, -1, 0); +} + +void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIMachineFrame() { + EmitARM64WinUnwindCode(Win64EH::UOP_PushMachFrame, -1, 0); +} + +void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIContext() { + EmitARM64WinUnwindCode(Win64EH::UOP_Context, -1, 0); +} + +void AArch64TargetWinCOFFStreamer::EmitARM64WinCFIClearUnwoundToCall() { + EmitARM64WinUnwindCode(Win64EH::UOP_ClearUnwoundToCall, -1, 0); +} + MCWinCOFFStreamer *createAArch64WinCOFFStreamer( MCContext &Context, std::unique_ptr MAB, std::unique_ptr OW, std::unique_ptr Emitter, diff --git a/llvm/test/MC/AArch64/seh.s b/llvm/test/MC/AArch64/seh.s --- a/llvm/test/MC/AArch64/seh.s +++ b/llvm/test/MC/AArch64/seh.s @@ -20,7 +20,7 @@ // CHECK-NEXT: } // CHECK: Section { // CHECK: Name: .xdata -// CHECK: RawDataSize: 48 +// CHECK: RawDataSize: 56 // CHECK: RelocationCount: 1 // CHECK: Characteristics [ // CHECK-NEXT: ALIGN_4BYTES @@ -41,7 +41,7 @@ // CHECK-NEXT: Relocations [ // CHECK-NEXT: Section (4) .xdata { -// CHECK-NEXT: 0x24 IMAGE_REL_ARM64_ADDR32NB __C_specific_handler +// CHECK-NEXT: 0x2C IMAGE_REL_ARM64_ADDR32NB __C_specific_handler // CHECK-NEXT: } // CHECK-NEXT: Section (5) .pdata { // CHECK-NEXT: 0x0 IMAGE_REL_ARM64_ADDR32NB func @@ -54,8 +54,12 @@ // CHECK-NEXT: Function: func // CHECK-NEXT: ExceptionRecord: .xdata // CHECK-NEXT: ExceptionData { -// CHECK-NEXT: FunctionLength: 72 +// CHECK-NEXT: FunctionLength: 100 // CHECK: Prologue [ +// CHECK-NEXT: 0xec ; clear unwound to call +// CHECK-NEXT: 0xea ; context +// CHECK-NEXT: 0xe9 ; machine frame +// CHECK-NEXT: 0xe8 ; trap frame // CHECK-NEXT: 0xe3 ; nop // CHECK-NEXT: 0xe202 ; add fp, sp, #16 // CHECK-NEXT: 0xdd41 ; str d13, [sp, #8] @@ -66,7 +70,10 @@ // CHECK-NEXT: 0x46 ; stp x29, x30, [sp, #48] // CHECK-NEXT: 0xd141 ; str x24, [sp, #8] // CHECK-NEXT: 0xd483 ; str x23, [sp, #-32]! +// CHECK-NEXT: 0xe6 ; save next // CHECK-NEXT: 0xc882 ; stp x21, x22, [sp, #16] +// CHECK-NEXT: 0xd6c2 ; stp x25, lr, [sp, #16] +// CHECK-NEXT: 0x24 ; stp x19, x20, [sp, #-32]! // CHECK-NEXT: 0xcc03 ; stp x19, x20, [sp, #-32]! // CHECK-NEXT: 0x83 ; stp x29, x30, [sp, #-32]! // CHECK-NEXT: 0xe1 ; mov fp, sp @@ -75,8 +82,8 @@ // CHECK-NEXT: ] // CHECK-NEXT: EpilogueScopes [ // CHECK-NEXT: EpilogueScope { -// CHECK-NEXT: StartOffset: 16 -// CHECK-NEXT: EpilogueStartIndex: 25 +// CHECK-NEXT: StartOffset: 23 +// CHECK-NEXT: EpilogueStartIndex: 33 // CHECK-NEXT: Opcodes [ // CHECK-NEXT: 0x01 ; add sp, #16 // CHECK-NEXT: 0xe4 ; end @@ -108,8 +115,14 @@ .seh_save_fplr_x 32 stp x19, x20, [sp, #-32]! .seh_save_regp_x x19, 32 + stp x19, x20, [sp, #-32]! + .seh_save_r19r20_x 32 + stp x25, x30, [sp, #16] + .seh_save_lrpair x25, 16 stp x21, x22, [sp, #16] .seh_save_regp x21, 16 + stp x23, x24, [sp, #32] + .seh_save_next str x23, [sp, #-32]! .seh_save_reg_x x23, 32 str x24, [sp, #8] @@ -130,6 +143,14 @@ .seh_add_fp 16 nop .seh_nop + nop + .seh_trap_frame + nop + .seh_pushframe + nop + .seh_context + nop + .seh_clear_unwound_to_call .seh_endprologue nop .seh_startepilogue diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.h b/llvm/tools/llvm-readobj/ARMWinEHPrinter.h --- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.h +++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.h @@ -120,6 +120,14 @@ bool Prologue); bool opcode_save_next(const uint8_t *Opcodes, unsigned &Offset, unsigned Length, bool Prologue); + bool opcode_trap_frame(const uint8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_machine_frame(const uint8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_context(const uint8_t *Opcodes, unsigned &Offset, unsigned Length, + bool Prologue); + bool opcode_clear_unwound_to_call(const uint8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); void decodeOpcodes(ArrayRef Opcodes, unsigned Offset, bool Prologue); diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp --- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -167,6 +167,11 @@ { 0xff, 0xe3, 1, &Decoder::opcode_nop }, { 0xff, 0xe4, 1, &Decoder::opcode_end }, { 0xff, 0xe5, 1, &Decoder::opcode_end_c }, + { 0xff, 0xe6, 1, &Decoder::opcode_save_next }, + { 0xff, 0xe8, 1, &Decoder::opcode_trap_frame }, + { 0xff, 0xe9, 1, &Decoder::opcode_machine_frame }, + { 0xff, 0xea, 1, &Decoder::opcode_context }, + { 0xff, 0xec, 1, &Decoder::opcode_clear_unwound_to_call }, }; void Decoder::printRegisters(const std::pair &RegisterMask) { @@ -776,6 +781,47 @@ return true; } +bool Decoder::opcode_save_next(const uint8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + if (Prologue) + SW.startLine() << format("0x%02x ; save next\n", OC[Offset]); + else + SW.startLine() << format("0x%02x ; restore next\n", + OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_trap_frame(const uint8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; trap frame\n", OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_machine_frame(const uint8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; machine frame\n", + OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_context(const uint8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; context\n", OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_clear_unwound_to_call(const uint8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; clear unwound to call\n", + OC[Offset]); + ++Offset; + return false; +} + void Decoder::decodeOpcodes(ArrayRef Opcodes, unsigned Offset, bool Prologue) { assert((!Prologue || Offset == 0) && "prologue should always use offset 0");