Skip to content

Commit

Permalink
[AArch64] - Return address signing dwarf support
Browse files Browse the repository at this point in the history
Functions that have signed return addresses need additional dwarf support:
- After signing the LR, and before authenticating it, the LR register is in a
  state the is unusable by a debugger or unwinder
- To account for this a new directive, .cfi_negate_ra_state, is added
- This directive says the signed state of the LR register has now changed,
  i.e. unsigned -> signed or signed -> unsigned
- This directive has the same CFA code as the SPARC directive GNU_window_save
  (0x2d), adding a macro to account for multiply defined codes
- This patch matches the gcc implementation of this support:
  https://patchwork.ozlabs.org/patch/800271/

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

llvm-svn: 343089
  • Loading branch information
Luke Cheeseman committed Sep 26, 2018
1 parent 4e8337e commit f755e68
Show file tree
Hide file tree
Showing 25 changed files with 192 additions and 75 deletions.
15 changes: 11 additions & 4 deletions llvm/include/llvm/BinaryFormat/Dwarf.def
Expand Up @@ -18,7 +18,8 @@
defined HANDLE_DW_VIRTUALITY || defined HANDLE_DW_DEFAULTED || \
defined HANDLE_DW_CC || defined HANDLE_DW_LNS || defined HANDLE_DW_LNE || \
defined HANDLE_DW_LNCT || defined HANDLE_DW_MACRO || \
defined HANDLE_DW_RLE || defined HANDLE_DW_CFA || \
defined HANDLE_DW_RLE || \
(defined HANDLE_DW_CFA && defined HANDLE_DW_CFA_PRED) || \
defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT || \
defined HANDLE_DWARF_SECTION || defined HANDLE_DW_IDX || \
defined HANDLE_DW_END)
Expand Down Expand Up @@ -85,6 +86,10 @@
#define HANDLE_DW_CFA(ID, NAME)
#endif

#ifndef HANDLE_DW_CFA_PRED
#define HANDLE_DW_CFA_PRED(ID, NAME, PRED)
#endif

#ifndef HANDLE_DW_APPLE_PROPERTY
#define HANDLE_DW_APPLE_PROPERTY(ID, NAME)
#endif
Expand Down Expand Up @@ -831,9 +836,10 @@ HANDLE_DW_CFA(0x14, val_offset)
HANDLE_DW_CFA(0x15, val_offset_sf)
HANDLE_DW_CFA(0x16, val_expression)
// Vendor extensions:
HANDLE_DW_CFA(0x1d, MIPS_advance_loc8)
HANDLE_DW_CFA(0x2d, GNU_window_save)
HANDLE_DW_CFA(0x2e, GNU_args_size)
HANDLE_DW_CFA_PRED(0x1d, MIPS_advance_loc8, SELECT_MIPS64)
HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC64)
HANDLE_DW_CFA_PRED(0x2d, AARCH64_negate_ra_state, SELECT_AARCH64)
HANDLE_DW_CFA_PRED(0x2e, GNU_args_size, SELECT_X86)

// Apple Objective-C Property Attributes.
// Keep this list in sync with clang's DeclSpec.h ObjCPropertyAttributeKind!
Expand Down Expand Up @@ -915,6 +921,7 @@ HANDLE_DW_IDX(0x05, type_hash)
#undef HANDLE_DW_MACRO
#undef HANDLE_DW_RLE
#undef HANDLE_DW_CFA
#undef HANDLE_DW_CFA_PRED
#undef HANDLE_DW_APPLE_PROPERTY
#undef HANDLE_DW_UT
#undef HANDLE_DWARF_SECTION
Expand Down
4 changes: 3 additions & 1 deletion llvm/include/llvm/BinaryFormat/Dwarf.h
Expand Up @@ -26,6 +26,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadicDetails.h"
#include "llvm/ADT/Triple.h"

namespace llvm {
class StringRef;
Expand Down Expand Up @@ -272,6 +273,7 @@ enum RangeListEntries {
/// Call frame instruction encodings.
enum CallFrameInfo {
#define HANDLE_DW_CFA(ID, NAME) DW_CFA_##NAME = ID,
#define HANDLE_DW_CFA_PRED(ID, NAME, ARCH) DW_CFA_##NAME = ID,
#include "llvm/BinaryFormat/Dwarf.def"
DW_CFA_extended = 0x00,

Expand Down Expand Up @@ -430,7 +432,7 @@ StringRef LNStandardString(unsigned Standard);
StringRef LNExtendedString(unsigned Encoding);
StringRef MacinfoString(unsigned Encoding);
StringRef RangeListEncodingString(unsigned Encoding);
StringRef CallFrameString(unsigned Encoding);
StringRef CallFrameString(unsigned Encoding, Triple::ArchType Arch);
StringRef ApplePropertyString(unsigned);
StringRef UnitTypeString(unsigned);
StringRef AtomTypeString(unsigned Atom);
Expand Down
3 changes: 2 additions & 1 deletion llvm/include/llvm/DebugInfo/DWARF/DWARFContext.h
Expand Up @@ -90,6 +90,7 @@ class DWARFContext : public DIContext {
bool CheckedForDWP = false;
std::string DWPName;

Triple::ArchType Arch;
std::unique_ptr<MCRegisterInfo> RegInfo;

/// Read compile units from the debug_info section (if necessary)
Expand Down Expand Up @@ -341,7 +342,7 @@ class DWARFContext : public DIContext {
/// Loads register info for the architecture of the provided object file.
/// Improves readability of dumped DWARF expressions. Requires the caller to
/// have initialized the relevant target descriptions.
Error loadRegisterInfo(const object::ObjectFile &Obj);
Error loadArchitectureInfo(const object::ObjectFile &Obj);

/// Get address size from CUs.
/// TODO: refactor compile_units() to make this const.
Expand Down
26 changes: 17 additions & 9 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h
Expand Up @@ -13,6 +13,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Triple.h"
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
#include "llvm/Support/Error.h"
Expand Down Expand Up @@ -59,9 +60,11 @@ class CFIProgram {
unsigned size() const { return (unsigned)Instructions.size(); }
bool empty() const { return Instructions.empty(); }

CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor)
CFIProgram(uint64_t CodeAlignmentFactor, int64_t DataAlignmentFactor,
Triple::ArchType Arch)
: CodeAlignmentFactor(CodeAlignmentFactor),
DataAlignmentFactor(DataAlignmentFactor) {}
DataAlignmentFactor(DataAlignmentFactor),
Arch(Arch) {}

/// Parse and store a sequence of CFI instructions from Data,
/// starting at *Offset and ending at EndOffset. *Offset is updated
Expand All @@ -76,6 +79,7 @@ class CFIProgram {
std::vector<Instruction> Instructions;
const uint64_t CodeAlignmentFactor;
const int64_t DataAlignmentFactor;
Triple::ArchType Arch;

/// Convenience method to add a new instruction with the given opcode.
void addInstruction(uint8_t Opcode) {
Expand Down Expand Up @@ -130,8 +134,9 @@ class FrameEntry {
enum FrameKind { FK_CIE, FK_FDE };

FrameEntry(FrameKind K, uint64_t Offset, uint64_t Length, uint64_t CodeAlign,
int64_t DataAlign)
: Kind(K), Offset(Offset), Length(Length), CFIs(CodeAlign, DataAlign) {}
int64_t DataAlign, Triple::ArchType Arch)
: Kind(K), Offset(Offset), Length(Length),
CFIs(CodeAlign, DataAlign, Arch) {}

virtual ~FrameEntry() {}

Expand Down Expand Up @@ -168,9 +173,9 @@ class CIE : public FrameEntry {
int64_t DataAlignmentFactor, uint64_t ReturnAddressRegister,
SmallString<8> AugmentationData, uint32_t FDEPointerEncoding,
uint32_t LSDAPointerEncoding, Optional<uint64_t> Personality,
Optional<uint32_t> PersonalityEnc)
Optional<uint32_t> PersonalityEnc, Triple::ArchType Arch)
: FrameEntry(FK_CIE, Offset, Length, CodeAlignmentFactor,
DataAlignmentFactor),
DataAlignmentFactor, Arch),
Version(Version), Augmentation(std::move(Augmentation)),
AddressSize(AddressSize), SegmentDescriptorSize(SegmentDescriptorSize),
CodeAlignmentFactor(CodeAlignmentFactor),
Expand Down Expand Up @@ -224,10 +229,11 @@ class FDE : public FrameEntry {
// is obtained lazily once it's actually required.
FDE(uint64_t Offset, uint64_t Length, int64_t LinkedCIEOffset,
uint64_t InitialLocation, uint64_t AddressRange, CIE *Cie,
Optional<uint64_t> LSDAAddress)
Optional<uint64_t> LSDAAddress, Triple::ArchType Arch)
: FrameEntry(FK_FDE, Offset, Length,
Cie ? Cie->getCodeAlignmentFactor() : 0,
Cie ? Cie->getDataAlignmentFactor() : 0),
Cie ? Cie->getDataAlignmentFactor() : 0,
Arch),
LinkedCIEOffset(LinkedCIEOffset), InitialLocation(InitialLocation),
AddressRange(AddressRange), LinkedCIE(Cie), LSDAAddress(LSDAAddress) {}

Expand Down Expand Up @@ -256,6 +262,7 @@ class FDE : public FrameEntry {

/// A parsed .debug_frame or .eh_frame section
class DWARFDebugFrame {
const Triple::ArchType Arch;
// True if this is parsing an eh_frame section.
const bool IsEH;
// Not zero for sane pointer values coming out of eh_frame
Expand All @@ -272,7 +279,8 @@ class DWARFDebugFrame {
// it is a .debug_frame section. EHFrameAddress should be different
// than zero for correct parsing of .eh_frame addresses when they
// use a PC-relative encoding.
DWARFDebugFrame(bool IsEH = false, uint64_t EHFrameAddress = 0);
DWARFDebugFrame(Triple::ArchType Arch,
bool IsEH = false, uint64_t EHFrameAddress = 0);
~DWARFDebugFrame();

/// Dump the section data into the given stream.
Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/MC/MCDwarf.h
Expand Up @@ -430,6 +430,7 @@ class MCCFIInstruction {
OpUndefined,
OpRegister,
OpWindowSave,
OpNegateRAState,
OpGnuArgsSize
};

Expand Down Expand Up @@ -509,6 +510,11 @@ class MCCFIInstruction {
return MCCFIInstruction(OpWindowSave, L, 0, 0, "");
}

/// .cfi_negate_ra_state AArch64 negate RA state.
static MCCFIInstruction createNegateRAState(MCSymbol *L) {
return MCCFIInstruction(OpNegateRAState, L, 0, 0, "");
}

/// .cfi_restore says that the rule for Register is now the same as it
/// was at the beginning of the function, after all initial instructions added
/// by .cfi_startproc were executed.
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Expand Up @@ -891,6 +891,7 @@ class MCStreamer {
virtual void EmitCFIUndefined(int64_t Register);
virtual void EmitCFIRegister(int64_t Register1, int64_t Register2);
virtual void EmitCFIWindowSave();
virtual void EmitCFINegateRAState();

virtual void EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc = SMLoc());
virtual void EmitWinCFIEndProc(SMLoc Loc = SMLoc());
Expand Down
20 changes: 19 additions & 1 deletion llvm/lib/BinaryFormat/Dwarf.cpp
Expand Up @@ -13,6 +13,7 @@

#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/ErrorHandling.h"

using namespace llvm;
Expand Down Expand Up @@ -455,14 +456,31 @@ StringRef llvm::dwarf::RangeListEncodingString(unsigned Encoding) {
}
}

StringRef llvm::dwarf::CallFrameString(unsigned Encoding) {
StringRef llvm::dwarf::CallFrameString(unsigned Encoding,
Triple::ArchType Arch) {
#define SELECT_AARCH64 (Arch == llvm::Triple::aarch64_be || Arch == llvm::Triple::aarch64)
#define SELECT_MIPS64 Arch == llvm::Triple::mips64
#define SELECT_SPARC64 Arch == llvm::Triple::sparcv9
#define SELECT_X86 (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64)
#define HANDLE_DW_CFA(ID, NAME)
#define HANDLE_DW_CFA_PRED(ID, NAME, PRED) \
if (ID == Encoding && PRED) \
return "DW_CFA_" #NAME;
#include "llvm/BinaryFormat/Dwarf.def"

switch (Encoding) {
default:
return StringRef();
#define HANDLE_DW_CFA_PRED(ID, NAME, PRED)
#define HANDLE_DW_CFA(ID, NAME) \
case DW_CFA_##NAME: \
return "DW_CFA_" #NAME;
#include "llvm/BinaryFormat/Dwarf.def"

#undef SELECT_X86
#undef SELECT_SPARC64
#undef SELECT_MIPS64
#undef SELECT_AARCH64
}
}

Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
Expand Up @@ -212,6 +212,9 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
case MCCFIInstruction::OpWindowSave:
OutStreamer->EmitCFIWindowSave();
break;
case MCCFIInstruction::OpNegateRAState:
OutStreamer->EmitCFINegateRAState();
break;
case MCCFIInstruction::OpSameValue:
OutStreamer->EmitCFISameValue(Inst.getRegister());
break;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/CFIInstrInserter.cpp
Expand Up @@ -207,6 +207,7 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
case MCCFIInstruction::OpUndefined:
case MCCFIInstruction::OpRegister:
case MCCFIInstruction::OpWindowSave:
case MCCFIInstruction::OpNegateRAState:
case MCCFIInstruction::OpGnuArgsSize:
break;
}
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/MIRParser/MILexer.cpp
Expand Up @@ -220,6 +220,7 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
.Case("undefined", MIToken::kw_cfi_undefined)
.Case("register", MIToken::kw_cfi_register)
.Case("window_save", MIToken::kw_cfi_window_save)
.Case("negate_ra_sign_state", MIToken::kw_cfi_aarch64_negate_ra_sign_state)
.Case("blockaddress", MIToken::kw_blockaddress)
.Case("intrinsic", MIToken::kw_intrinsic)
.Case("target-index", MIToken::kw_target_index)
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/MIRParser/MILexer.h
Expand Up @@ -89,6 +89,7 @@ struct MIToken {
kw_cfi_restore_state,
kw_cfi_undefined,
kw_cfi_window_save,
kw_cfi_aarch64_negate_ra_sign_state,
kw_blockaddress,
kw_intrinsic,
kw_target_index,
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/MIRParser/MIParser.cpp
Expand Up @@ -1816,6 +1816,9 @@ bool MIParser::parseCFIOperand(MachineOperand &Dest) {
case MIToken::kw_cfi_window_save:
CFIIndex = MF.addFrameInst(MCCFIInstruction::createWindowSave(nullptr));
break;
case MIToken::kw_cfi_aarch64_negate_ra_sign_state:
CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
break;
case MIToken::kw_cfi_escape: {
std::string Values;
if (parseCFIEscapeValues(Values))
Expand Down Expand Up @@ -2108,6 +2111,7 @@ bool MIParser::parseMachineOperand(MachineOperand &Dest,
case MIToken::kw_cfi_restore_state:
case MIToken::kw_cfi_undefined:
case MIToken::kw_cfi_window_save:
case MIToken::kw_cfi_aarch64_negate_ra_sign_state:
return parseCFIOperand(Dest);
case MIToken::kw_blockaddress:
return parseBlockAddressOperand(Dest);
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/MachineOperand.cpp
Expand Up @@ -696,6 +696,11 @@ static void printCFI(raw_ostream &OS, const MCCFIInstruction &CFI,
if (MCSymbol *Label = CFI.getLabel())
MachineOperand::printSymbol(OS, *Label);
break;
case MCCFIInstruction::OpNegateRAState:
OS << "negate_ra_sign_state ";
if (MCSymbol *Label = CFI.getLabel())
MachineOperand::printSymbol(OS, *Label);
break;
default:
// TODO: Print the other CFI Operations.
OS << "<unserializable cfi directive>";
Expand Down
8 changes: 5 additions & 3 deletions llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
Expand Up @@ -724,7 +724,7 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() {
// http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
DWARFDataExtractor debugFrameData(DObj->getDebugFrameSection(),
isLittleEndian(), DObj->getAddressSize());
DebugFrame.reset(new DWARFDebugFrame(false /* IsEH */));
DebugFrame.reset(new DWARFDebugFrame(Arch, false /* IsEH */));
DebugFrame->parse(debugFrameData);
return DebugFrame.get();
}
Expand All @@ -735,7 +735,7 @@ const DWARFDebugFrame *DWARFContext::getEHFrame() {

DWARFDataExtractor debugFrameData(DObj->getEHFrameSection(), isLittleEndian(),
DObj->getAddressSize());
DebugFrame.reset(new DWARFDebugFrame(true /* IsEH */));
DebugFrame.reset(new DWARFDebugFrame(Arch, true /* IsEH */));
DebugFrame->parse(debugFrameData);
return DebugFrame.get();
}
Expand Down Expand Up @@ -1581,9 +1581,11 @@ DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
return llvm::make_unique<DWARFContext>(std::move(DObj), "");
}

Error DWARFContext::loadRegisterInfo(const object::ObjectFile &Obj) {
Error DWARFContext::loadArchitectureInfo(const object::ObjectFile &Obj) {
// Detect the architecture from the object file. We usually don't need OS
// info to lookup a target and create register info.
Arch = Triple::ArchType(Obj.getArch());

Triple TT;
TT.setArch(Triple::ArchType(Obj.getArch()));
TT.setVendor(Triple::UnknownVendor);
Expand Down
13 changes: 7 additions & 6 deletions llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
Expand Up @@ -225,7 +225,7 @@ void CFIProgram::printOperand(raw_ostream &OS, const MCRegisterInfo *MRI,
switch (Type) {
case OT_Unset: {
OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
auto OpcodeName = CallFrameString(Opcode);
auto OpcodeName = CallFrameString(Opcode, Arch);
if (!OpcodeName.empty())
OS << " " << OpcodeName;
else
Expand Down Expand Up @@ -279,7 +279,7 @@ void CFIProgram::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
if (Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK)
Opcode &= DWARF_CFI_PRIMARY_OPCODE_MASK;
OS.indent(2 * IndentLevel);
OS << CallFrameString(Opcode) << ":";
OS << CallFrameString(Opcode, Arch) << ":";
for (unsigned i = 0; i < Instr.Ops.size(); ++i)
printOperand(OS, MRI, IsEH, Instr, i, Instr.Ops[i]);
OS << '\n';
Expand Down Expand Up @@ -325,8 +325,9 @@ void FDE::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH) const {
OS << "\n";
}

DWARFDebugFrame::DWARFDebugFrame(bool IsEH, uint64_t EHFrameAddress)
: IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch,
bool IsEH, uint64_t EHFrameAddress)
: Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}

DWARFDebugFrame::~DWARFDebugFrame() = default;

Expand Down Expand Up @@ -460,7 +461,7 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {
StartOffset, Length, Version, AugmentationString, AddressSize,
SegmentDescriptorSize, CodeAlignmentFactor, DataAlignmentFactor,
ReturnAddressRegister, AugmentationData, FDEPointerEncoding,
LSDAPointerEncoding, Personality, PersonalityEncoding);
LSDAPointerEncoding, Personality, PersonalityEncoding, Arch);
CIEs[StartOffset] = Cie.get();
Entries.emplace_back(std::move(Cie));
} else {
Expand Down Expand Up @@ -512,7 +513,7 @@ void DWARFDebugFrame::parse(DWARFDataExtractor Data) {

Entries.emplace_back(new FDE(StartOffset, Length, CIEPointer,
InitialLocation, AddressRange,
Cie, LSDAAddress));
Cie, LSDAAddress, Arch));
}

if (Error E =
Expand Down

0 comments on commit f755e68

Please sign in to comment.