Skip to content

Commit

Permalink
[Dwarf/AArch64] Return address signing B key dwarf support
Browse files Browse the repository at this point in the history
- When signing return addresses with -msign-return-address=<scope>{+<key>},
  either the A key instructions or the B key instructions can be used. To
  correctly authenticate the return address, the unwinder/debugger must know
  which key was used to sign the return address.
- When and exception is thrown or a break point reached, it may be necessary to
  unwind the stack. To accomplish this, the unwinder/debugger must be able to
  first authenticate an the return address if it has been signed.
- To enable this, the augmentation string of CIEs has been extended to allow
  inclusion of a 'B' character. Functions that are signed using the B key
  variant of the instructions should have and FDE whose associated CIE has a 'B'
  in the augmentation string.
- One must also be able to preserve these semantics when first stepping from a
  high level language into assembly and then, as a second step, into an object
  file. To achieve this, I have introduced a new assembly directive
  '.cfi_b_key_frame ', that tells the assembler the current frame uses return
  address signing with the B key.
- This ensures that the FDE is associated with a CIE that has 'B' in the
  augmentation string.

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

llvm-svn: 349895
  • Loading branch information
Luke Cheeseman committed Dec 21, 2018
1 parent 82fbb66 commit 41a9e53
Show file tree
Hide file tree
Showing 14 changed files with 161 additions and 16 deletions.
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCDwarf.h
Expand Up @@ -599,6 +599,7 @@ struct MCDwarfFrameInfo {
bool IsSignalFrame = false;
bool IsSimple = false;
unsigned RAReg = static_cast<unsigned>(INT_MAX);
bool IsBKeyFrame = false;
};

class MCDwarfFrameEmitter {
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Expand Up @@ -806,6 +806,8 @@ class MCStreamer {
Optional<StringRef> Source,
unsigned CUID = 0);

virtual void EmitCFIBKeyFrame();

/// This implements the DWARF2 '.loc fileno lineno ...' assembler
/// directive.
virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line,
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
Expand Up @@ -446,6 +446,11 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
StartAugmentationOffset = Offset;
EndAugmentationOffset = Offset +
static_cast<uint32_t>(*AugmentationLength);
break;
case 'B':
// B-Key is used for signing functions associated with this
// augmentation string
break;
}
}

Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/MC/MCAsmStreamer.cpp
Expand Up @@ -266,6 +266,7 @@ class MCAsmStreamer final : public MCStreamer {
void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override;

void EmitIdent(StringRef IdentString) override;
void EmitCFIBKeyFrame() override;
void EmitCFISections(bool EH, bool Debug) override;
void EmitCFIDefCfa(int64_t Register, int64_t Offset) override;
void EmitCFIDefCfaOffset(int64_t Offset) override;
Expand Down Expand Up @@ -1602,6 +1603,12 @@ void MCAsmStreamer::EmitCFIReturnColumn(int64_t Register) {
EmitEOL();
}

void MCAsmStreamer::EmitCFIBKeyFrame() {
MCStreamer::EmitCFIBKeyFrame();
OS << "\t.cfi_b_key_frame";
EmitEOL();
}

void MCAsmStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) {
MCStreamer::EmitWinCFIStartProc(Symbol, Loc);

Expand Down
29 changes: 17 additions & 12 deletions llvm/lib/MC/MCDwarf.cpp
Expand Up @@ -1565,9 +1565,8 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(const MCDwarfFrameInfo &Frame) {
uint8_t CIEVersion = getCIEVersion(IsEH, context.getDwarfVersion());
Streamer.EmitIntValue(CIEVersion, 1);

// Augmentation String
SmallString<8> Augmentation;
if (IsEH) {
SmallString<8> Augmentation;
Augmentation += "z";
if (Frame.Personality)
Augmentation += "P";
Expand All @@ -1576,6 +1575,8 @@ const MCSymbol &FrameEmitterImpl::EmitCIE(const MCDwarfFrameInfo &Frame) {
Augmentation += "R";
if (Frame.IsSignalFrame)
Augmentation += "S";
if (Frame.IsBKeyFrame)
Augmentation += "B";
Streamer.EmitBytes(Augmentation);
}
Streamer.EmitIntValue(0, 1);
Expand Down Expand Up @@ -1730,32 +1731,36 @@ namespace {

struct CIEKey {
static const CIEKey getEmptyKey() {
return CIEKey(nullptr, 0, -1, false, false, static_cast<unsigned>(INT_MAX));
return CIEKey(nullptr, 0, -1, false, false, static_cast<unsigned>(INT_MAX),
false);
}

static const CIEKey getTombstoneKey() {
return CIEKey(nullptr, -1, 0, false, false, static_cast<unsigned>(INT_MAX));
return CIEKey(nullptr, -1, 0, false, false, static_cast<unsigned>(INT_MAX),
false);
}

CIEKey(const MCSymbol *Personality, unsigned PersonalityEncoding,
unsigned LSDAEncoding, bool IsSignalFrame, bool IsSimple,
unsigned RAReg)
unsigned RAReg, bool IsBKeyFrame)
: Personality(Personality), PersonalityEncoding(PersonalityEncoding),
LsdaEncoding(LSDAEncoding), IsSignalFrame(IsSignalFrame),
IsSimple(IsSimple), RAReg(RAReg) {}
IsSimple(IsSimple), RAReg(RAReg), IsBKeyFrame(IsBKeyFrame) {}

explicit CIEKey(const MCDwarfFrameInfo &Frame)
: Personality(Frame.Personality),
PersonalityEncoding(Frame.PersonalityEncoding),
LsdaEncoding(Frame.LsdaEncoding), IsSignalFrame(Frame.IsSignalFrame),
IsSimple(Frame.IsSimple), RAReg(Frame.RAReg) {}
IsSimple(Frame.IsSimple), RAReg(Frame.RAReg),
IsBKeyFrame(Frame.IsBKeyFrame) {}

const MCSymbol *Personality;
unsigned PersonalityEncoding;
unsigned LsdaEncoding;
bool IsSignalFrame;
bool IsSimple;
unsigned RAReg;
bool IsBKeyFrame;
};

} // end anonymous namespace
Expand All @@ -1767,18 +1772,18 @@ template <> struct DenseMapInfo<CIEKey> {
static CIEKey getTombstoneKey() { return CIEKey::getTombstoneKey(); }

static unsigned getHashValue(const CIEKey &Key) {
return static_cast<unsigned>(
hash_combine(Key.Personality, Key.PersonalityEncoding, Key.LsdaEncoding,
Key.IsSignalFrame, Key.IsSimple, Key.RAReg));
return static_cast<unsigned>(hash_combine(
Key.Personality, Key.PersonalityEncoding, Key.LsdaEncoding,
Key.IsSignalFrame, Key.IsSimple, Key.RAReg, Key.IsBKeyFrame));
}

static bool isEqual(const CIEKey &LHS, const CIEKey &RHS) {
return LHS.Personality == RHS.Personality &&
LHS.PersonalityEncoding == RHS.PersonalityEncoding &&
LHS.LsdaEncoding == RHS.LsdaEncoding &&
LHS.IsSignalFrame == RHS.IsSignalFrame &&
LHS.IsSimple == RHS.IsSimple &&
LHS.RAReg == RHS.RAReg;
LHS.IsSimple == RHS.IsSimple && LHS.RAReg == RHS.RAReg &&
LHS.IsBKeyFrame == RHS.IsBKeyFrame;
}
};

Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/MC/MCParser/AsmParser.cpp
Expand Up @@ -495,6 +495,7 @@ class AsmParser : public MCAsmParser {
DK_CFI_UNDEFINED,
DK_CFI_REGISTER,
DK_CFI_WINDOW_SAVE,
DK_CFI_B_KEY_FRAME,
DK_MACROS_ON,
DK_MACROS_OFF,
DK_ALTMACRO,
Expand Down Expand Up @@ -5293,6 +5294,7 @@ void AsmParser::initializeDirectiveKindMap() {
DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;
DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;
DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;
DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;
DirectiveKindMap[".macros_on"] = DK_MACROS_ON;
DirectiveKindMap[".macros_off"] = DK_MACROS_OFF;
DirectiveKindMap[".macro"] = DK_MACRO;
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/MC/MCStreamer.cpp
Expand Up @@ -221,6 +221,13 @@ void MCStreamer::emitDwarfFile0Directive(StringRef Directory,
Source);
}

void MCStreamer::EmitCFIBKeyFrame() {
MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
if (!CurFrame)
return;
CurFrame->IsBKeyFrame = true;
}

void MCStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line,
unsigned Column, unsigned Flags,
unsigned Isa,
Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
Expand Up @@ -716,6 +716,19 @@ void AArch64AsmPrinter::EmitInstruction(const MachineInstr *MI) {
OutStreamer->EmitRawText(StringRef(OS.str()));
}
return;

case AArch64::EMITBKEY: {
ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType();
if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
ExceptionHandlingType != ExceptionHandling::ARM)
return;

if (needsCFIMoves() == CFI_M_None)
return;

OutStreamer->EmitCFIBKeyFrame();
return;
}
}

// Tail calls use pseudo instructions so they have the proper code-gen
Expand Down
13 changes: 9 additions & 4 deletions llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
Expand Up @@ -816,10 +816,15 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
DebugLoc DL;

if (ShouldSignReturnAddress(MF)) {
BuildMI(
MBB, MBBI, DL,
TII->get(ShouldSignWithAKey(MF) ? AArch64::PACIASP : AArch64::PACIBSP))
.setMIFlag(MachineInstr::FrameSetup);
if (ShouldSignWithAKey(MF))
BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIASP))
.setMIFlag(MachineInstr::FrameSetup);
else {
BuildMI(MBB, MBBI, DL, TII->get(AArch64::EMITBKEY))
.setMIFlag(MachineInstr::FrameSetup);
BuildMI(MBB, MBBI, DL, TII->get(AArch64::PACIBSP))
.setMIFlag(MachineInstr::FrameSetup);
}

unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.td
Expand Up @@ -1619,6 +1619,10 @@ def TLSDESCCALL : Pseudo<(outs), (ins i64imm:$sym), []>, Sched<[]> {
let AsmString = ".tlsdesccall $sym";
}

// Pseudo instruction to tell the streamer to emit a 'B' character into the
// augmentation string.
def EMITBKEY : Pseudo<(outs), (ins), []>, Sched<[]> {}

// FIXME: maybe the scratch register used shouldn't be fixed to X1?
// FIXME: can "hasSideEffects be dropped?
let isCall = 1, Defs = [LR, X0, X1], hasSideEffects = 1,
Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
Expand Up @@ -176,6 +176,7 @@ class AArch64AsmParser : public MCTargetAsmParser {
bool parseDirectiveReq(StringRef Name, SMLoc L);
bool parseDirectiveUnreq(SMLoc L);
bool parseDirectiveCFINegateRAState();
bool parseDirectiveCFIBKeyFrame();

bool validateInstruction(MCInst &Inst, SMLoc &IDLoc,
SmallVectorImpl<SMLoc> &Loc);
Expand Down Expand Up @@ -5030,6 +5031,8 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
parseDirectiveInst(Loc);
else if (IDVal == ".cfi_negate_ra_state")
parseDirectiveCFINegateRAState();
else if (IDVal == ".cfi_b_key_frame")
parseDirectiveCFIBKeyFrame();
else if (IsMachO) {
if (IDVal == MCLOHDirectiveName())
parseDirectiveLOH(IDVal, Loc);
Expand Down Expand Up @@ -5410,6 +5413,16 @@ bool AArch64AsmParser::parseDirectiveCFINegateRAState() {
return false;
}

/// parseDirectiveCFIBKeyFrame
/// ::= .cfi_b_key
bool AArch64AsmParser::parseDirectiveCFIBKeyFrame() {
if (parseToken(AsmToken::EndOfStatement,
"unexpected token in '.cfi_b_key_frame'"))
return true;
getStreamer().EmitCFIBKeyFrame();
return false;
}

bool
AArch64AsmParser::classifySymbolRef(const MCExpr *Expr,
AArch64MCExpr::VariantKind &ELFRefKind,
Expand Down
48 changes: 48 additions & 0 deletions llvm/test/CodeGen/MIR/AArch64/return-address-signing.mir
@@ -0,0 +1,48 @@
# RUN: llc -mtriple=aarch64-arm-none-eabi -run-pass=prologepilog -o - %s 2>&1 | FileCheck %s
--- |
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-arm-none-eabi"

define dso_local i32 @foo() "sign-return-address"="all" "sign-return-address-key"="a_key" {
entry:
ret i32 2
}

define dso_local i32 @bar() "sign-return-address"="all" "sign-return-address-key"="b_key" {
entry:
ret i32 2
}
...
---
#CHECK: foo
name: foo
alignment: 2
tracksRegLiveness: true
frameInfo:
maxCallFrameSize: 0
#CHECK: frame-setup PACIASP implicit-def $lr, implicit $lr, implicit $sp
#CHECK: frame-setup CFI_INSTRUCTION negate_ra_sign_state
#CHECK: frame-destroy AUTIASP implicit-def $lr, implicit $lr, implicit $sp
body: |
bb.0.entry:
$w0 = MOVi32imm 2
RET_ReallyLR implicit killed $w0
...
---
#CHECK: bar
name: bar
alignment: 2
tracksRegLiveness: true
frameInfo:
maxCallFrameSize: 0
#CHECK: frame-setup EMITBKEY
#CHECK: frame-setup PACIBSP implicit-def $lr, implicit $lr, implicit $sp
#CHECK: frame-setup CFI_INSTRUCTION negate_ra_sign_state
#CHECK: frame-destroy AUTIBSP implicit-def $lr, implicit $lr, implicit $sp
body: |
bb.0.entry:
$w0 = MOVi32imm 2
RET_ReallyLR implicit killed $w0
...
27 changes: 27 additions & 0 deletions llvm/test/DebugInfo/AArch64/return-address-signing.ll
@@ -0,0 +1,27 @@
; RUN: llc -mtriple=aarch64-arm-none-eabi < %s -filetype=obj -o - \
; RUN: | llvm-dwarfdump -v - | FileCheck -check-prefix=CHECK %s

;CHECK: CIE
;CHECK: Augmentation: "zR"
define i32 @foo() "sign-return-address"="all" {
ret i32 0
}

;CHECK: CIE
;CHECK: Augmentation: "zRB"

define i32 @bar() "sign-return-address"="all" "sign-return-address-key"="b_key" {
ret i32 0
}

;CHECK-NOT: CIE

define i32 @baz() "sign-return-address"="all" nounwind {
ret i32 0
}

;CHECK-NOT: CIE

define i32 @qux() "sign-return-address"="all" "sign-return-address-key"="b_key" nounwind {
ret i32 0
}
6 changes: 6 additions & 0 deletions llvm/test/MC/ELF/cfi-b-key-frame.s
@@ -0,0 +1,6 @@
// RUN: llvm-mc -filetype=obj -triple aarch64-arm-none-eabi %s -o - | llvm-dwarfdump - -v | FileCheck %s
#CHECK: Augmentation: "zRB"
f1:
.cfi_startproc
.cfi_b_key_frame
.cfi_endproc

0 comments on commit 41a9e53

Please sign in to comment.