From 977b537d0fcb82508f879ded21fb8a53810b2337 Mon Sep 17 00:00:00 2001 From: Jake Ehrlich Date: Fri, 1 Dec 2017 21:44:27 +0000 Subject: [PATCH] [MC] Handle unknown literal register numbers in .cfi_* directives r230670 introduced a step to map EH register numbers to standard DWARF register numbers. This failed to consider the case when a user .cfi_* directive uses an integer literal rather than a register name, to specify a DWARF register number that has no corresponding LLVM register number (e.g. a special register that the compiler and assembler have no name for). Fixes PR34028. Patch by Roland McGrath Differential Revision: https://reviews.llvm.org/D36493 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@319586 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/MC/MCRegisterInfo.h | 9 +++++++++ lib/MC/MCAsmStreamer.cpp | 13 +++++++++---- lib/MC/MCDwarf.cpp | 12 ++++++------ lib/MC/MCRegisterInfo.cpp | 28 ++++++++++++++++++++++++++++ test/MC/AsmParser/cfi-unknown-register.s | 7 +++++++ 5 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 test/MC/AsmParser/cfi-unknown-register.s diff --git a/include/llvm/MC/MCRegisterInfo.h b/include/llvm/MC/MCRegisterInfo.h index de98abe0dc4..c57c9ef709d 100644 --- a/include/llvm/MC/MCRegisterInfo.h +++ b/include/llvm/MC/MCRegisterInfo.h @@ -407,6 +407,15 @@ public: /// \brief Map a dwarf register back to a target register. int getLLVMRegNum(unsigned RegNum, bool isEH) const; + /// \brief Map a DWARF EH register back to a target register (same as + /// getLLVMRegNum(RegNum, true)) but return -1 if there is no mapping, + /// rather than asserting that there must be one. + int getLLVMRegNumFromEH(unsigned RegNum) const; + + /// \brief Map a target EH register number to an equivalent DWARF register + /// number. + int getDwarfRegNumFromDwarfEHRegNum(unsigned RegNum) const; + /// \brief Map a target register to an equivalent SEH register /// number. Returns LLVM register number if there is no equivalent value. int getSEHRegNum(unsigned RegNum) const; diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 44bac8eabdc..d1b475f2ca0 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -1296,12 +1296,17 @@ void MCAsmStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { void MCAsmStreamer::EmitRegisterName(int64_t Register) { if (!MAI->useDwarfRegNumForCFI()) { + // User .cfi_* directives can use arbitrary DWARF register numbers, not + // just ones that map to LLVM register numbers and have known names. + // Fall back to using the original number directly if no name is known. const MCRegisterInfo *MRI = getContext().getRegisterInfo(); - unsigned LLVMRegister = MRI->getLLVMRegNum(Register, true); - InstPrinter->printRegName(OS, LLVMRegister); - } else { - OS << Register; + int LLVMRegister = MRI->getLLVMRegNumFromEH(Register); + if (LLVMRegister != -1) { + InstPrinter->printRegName(OS, LLVMRegister); + return; + } } + OS << Register; } void MCAsmStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index a36ff4cb907..3dc0786e445 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -1057,8 +1057,8 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { unsigned Reg1 = Instr.getRegister(); unsigned Reg2 = Instr.getRegister2(); if (!IsEH) { - Reg1 = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg1, true), false); - Reg2 = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg2, true), false); + Reg1 = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg1); + Reg2 = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg2); } Streamer.EmitIntValue(dwarf::DW_CFA_register, 1); Streamer.EmitULEB128IntValue(Reg1); @@ -1094,7 +1094,7 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { case MCCFIInstruction::OpDefCfa: { unsigned Reg = Instr.getRegister(); if (!IsEH) - Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false); + Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg); Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1); Streamer.EmitULEB128IntValue(Reg); CFAOffset = -Instr.getOffset(); @@ -1105,7 +1105,7 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { case MCCFIInstruction::OpDefCfaRegister: { unsigned Reg = Instr.getRegister(); if (!IsEH) - Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false); + Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg); Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1); Streamer.EmitULEB128IntValue(Reg); @@ -1118,7 +1118,7 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { unsigned Reg = Instr.getRegister(); if (!IsEH) - Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false); + Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg); int Offset = Instr.getOffset(); if (IsRelative) @@ -1154,7 +1154,7 @@ void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) { case MCCFIInstruction::OpRestore: { unsigned Reg = Instr.getRegister(); if (!IsEH) - Reg = MRI->getDwarfRegNum(MRI->getLLVMRegNum(Reg, true), false); + Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg); Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1); return; } diff --git a/lib/MC/MCRegisterInfo.cpp b/lib/MC/MCRegisterInfo.cpp index 0f76c1838b5..8e47963b441 100644 --- a/lib/MC/MCRegisterInfo.cpp +++ b/lib/MC/MCRegisterInfo.cpp @@ -88,6 +88,34 @@ int MCRegisterInfo::getLLVMRegNum(unsigned RegNum, bool isEH) const { return I->ToReg; } +int MCRegisterInfo::getLLVMRegNumFromEH(unsigned RegNum) const { + const DwarfLLVMRegPair *M = EHDwarf2LRegs; + unsigned Size = EHDwarf2LRegsSize; + + if (!M) + return -1; + DwarfLLVMRegPair Key = { RegNum, 0 }; + const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key); + if (I == M+Size || I->FromReg != RegNum) + return -1; + return I->ToReg; +} + +int MCRegisterInfo::getDwarfRegNumFromDwarfEHRegNum(unsigned RegNum) const { + // On ELF platforms, DWARF EH register numbers are the same as DWARF + // other register numbers. On Darwin x86, they differ and so need to be + // mapped. The .cfi_* directives accept integer literals as well as + // register names and should generate exactly what the assembly code + // asked for, so there might be DWARF/EH register numbers that don't have + // a corresponding LLVM register number at all. So if we can't map the + // EH register number to an LLVM register number, assume it's just a + // valid DWARF register number as is. + int LRegNum = getLLVMRegNumFromEH(RegNum); + if (LRegNum != -1) + return getDwarfRegNum(LRegNum, false); + return RegNum; +} + int MCRegisterInfo::getSEHRegNum(unsigned RegNum) const { const DenseMap::const_iterator I = L2SEHRegs.find(RegNum); if (I == L2SEHRegs.end()) return (int)RegNum; diff --git a/test/MC/AsmParser/cfi-unknown-register.s b/test/MC/AsmParser/cfi-unknown-register.s new file mode 100644 index 00000000000..ff0a06d9813 --- /dev/null +++ b/test/MC/AsmParser/cfi-unknown-register.s @@ -0,0 +1,7 @@ +// RUN: llvm-mc -filetype=asm -triple x86_64-pc-linux-gnu %s 2>&1 | FileCheck %s + +.cfi_sections .debug_frame +.cfi_startproc +.cfi_rel_offset 99, 0 +// CHECK: .cfi_rel_offset 99, 0 +.cfi_endproc -- 2.11.0