1 //===-- CodeGen/AsmPrinter/DwarfException.cpp - Dwarf Exception Impl ------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains support for writing DWARF exception info into asm files. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "DwarfException.h" 14 #include "llvm/BinaryFormat/Dwarf.h" 15 #include "llvm/CodeGen/AsmPrinter.h" 16 #include "llvm/CodeGen/MachineFunction.h" 17 #include "llvm/CodeGen/MachineModuleInfo.h" 18 #include "llvm/MC/MCAsmInfo.h" 19 #include "llvm/MC/MCContext.h" 20 #include "llvm/MC/MCStreamer.h" 21 #include "llvm/Target/TargetLoweringObjectFile.h" 22 #include "llvm/Target/TargetMachine.h" 23 #include "llvm/Target/TargetOptions.h" 24 using namespace llvm; 25 26 DwarfCFIExceptionBase::DwarfCFIExceptionBase(AsmPrinter *A) : EHStreamer(A) {} 27 28 void DwarfCFIExceptionBase::markFunctionEnd() { 29 endFragment(); 30 31 // Map all labels and get rid of any dead landing pads. 32 if (!Asm->MF->getLandingPads().empty()) { 33 MachineFunction *NonConstMF = const_cast<MachineFunction*>(Asm->MF); 34 NonConstMF->tidyLandingPads(); 35 } 36 } 37 38 void DwarfCFIExceptionBase::endFragment() { 39 if (shouldEmitCFI && !Asm->MF->hasBBSections()) 40 Asm->OutStreamer->emitCFIEndProc(); 41 } 42 43 DwarfCFIException::DwarfCFIException(AsmPrinter *A) 44 : DwarfCFIExceptionBase(A) {} 45 46 DwarfCFIException::~DwarfCFIException() = default; 47 48 /// endModule - Emit all exception information that should come after the 49 /// content. 50 void DwarfCFIException::endModule() { 51 // SjLj uses this pass and it doesn't need this info. 52 if (!Asm->MAI->usesCFIForEH()) 53 return; 54 55 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 56 57 unsigned PerEncoding = TLOF.getPersonalityEncoding(); 58 59 if ((PerEncoding & 0x80) != dwarf::DW_EH_PE_indirect) 60 return; 61 62 // Emit references to all used personality functions 63 for (const Function *Personality : MMI->getPersonalities()) { 64 if (!Personality) 65 continue; 66 MCSymbol *Sym = Asm->getSymbol(Personality); 67 TLOF.emitPersonalityValue(*Asm->OutStreamer, Asm->getDataLayout(), Sym); 68 } 69 } 70 71 static MCSymbol *getExceptionSym(AsmPrinter *Asm, 72 const MachineBasicBlock *MBB) { 73 return Asm->getMBBExceptionSym(*MBB); 74 } 75 76 void DwarfCFIException::beginFunction(const MachineFunction *MF) { 77 shouldEmitPersonality = shouldEmitLSDA = false; 78 const Function &F = MF->getFunction(); 79 80 // If any landing pads survive, we need an EH table. 81 bool hasLandingPads = !MF->getLandingPads().empty(); 82 83 // See if we need frame move info. 84 bool shouldEmitMoves = 85 Asm->getFunctionCFISectionType(*MF) != AsmPrinter::CFISection::None; 86 87 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 88 unsigned PerEncoding = TLOF.getPersonalityEncoding(); 89 const Function *Per = nullptr; 90 if (F.hasPersonalityFn()) 91 Per = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts()); 92 93 // Emit a personality function even when there are no landing pads 94 forceEmitPersonality = 95 // ...if a personality function is explicitly specified 96 F.hasPersonalityFn() && 97 // ... and it's not known to be a noop in the absence of invokes 98 !isNoOpWithoutInvoke(classifyEHPersonality(Per)) && 99 // ... and we're not explicitly asked not to emit it 100 F.needsUnwindTableEntry(); 101 102 shouldEmitPersonality = 103 (forceEmitPersonality || 104 (hasLandingPads && PerEncoding != dwarf::DW_EH_PE_omit)) && 105 Per; 106 107 unsigned LSDAEncoding = TLOF.getLSDAEncoding(); 108 shouldEmitLSDA = shouldEmitPersonality && 109 LSDAEncoding != dwarf::DW_EH_PE_omit; 110 111 const MCAsmInfo &MAI = *MF->getMMI().getContext().getAsmInfo(); 112 if (MAI.getExceptionHandlingType() != ExceptionHandling::None) 113 shouldEmitCFI = 114 MAI.usesCFIForEH() && (shouldEmitPersonality || shouldEmitMoves); 115 else 116 shouldEmitCFI = Asm->needsCFIForDebug() && shouldEmitMoves; 117 118 beginFragment(&*MF->begin(), getExceptionSym); 119 } 120 121 void DwarfCFIException::beginFragment(const MachineBasicBlock *MBB, 122 ExceptionSymbolProvider ESP) { 123 if (!shouldEmitCFI) 124 return; 125 126 if (!hasEmittedCFISections) { 127 AsmPrinter::CFISection CFISecType = Asm->getModuleCFISectionType(); 128 // If we don't say anything it implies `.cfi_sections .eh_frame`, so we 129 // chose not to be verbose in that case. And with `ForceDwarfFrameSection`, 130 // we should always emit .debug_frame. 131 if (CFISecType == AsmPrinter::CFISection::Debug || 132 Asm->TM.Options.ForceDwarfFrameSection) 133 Asm->OutStreamer->emitCFISections( 134 CFISecType == AsmPrinter::CFISection::EH, true); 135 hasEmittedCFISections = true; 136 } 137 138 Asm->OutStreamer->emitCFIStartProc(/*IsSimple=*/false); 139 140 // Indicate personality routine, if any. 141 if (!shouldEmitPersonality) 142 return; 143 144 auto &F = MBB->getParent()->getFunction(); 145 auto *P = dyn_cast<Function>(F.getPersonalityFn()->stripPointerCasts()); 146 assert(P && "Expected personality function"); 147 148 // If we are forced to emit this personality, make sure to record 149 // it because it might not appear in any landingpad 150 if (forceEmitPersonality) 151 MMI->addPersonality(P); 152 153 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 154 unsigned PerEncoding = TLOF.getPersonalityEncoding(); 155 const MCSymbol *Sym = TLOF.getCFIPersonalitySymbol(P, Asm->TM, MMI); 156 Asm->OutStreamer->emitCFIPersonality(Sym, PerEncoding); 157 158 // Provide LSDA information. 159 if (shouldEmitLSDA) 160 Asm->OutStreamer->emitCFILsda(ESP(Asm, MBB), TLOF.getLSDAEncoding()); 161 } 162 163 /// endFunction - Gather and emit post-function exception information. 164 /// 165 void DwarfCFIException::endFunction(const MachineFunction *MF) { 166 if (!shouldEmitPersonality) 167 return; 168 169 emitExceptionTable(); 170 } 171 172 void DwarfCFIException::beginBasicBlock(const MachineBasicBlock &MBB) { 173 beginFragment(&MBB, getExceptionSym); 174 } 175 176 void DwarfCFIException::endBasicBlock(const MachineBasicBlock &MBB) { 177 if (shouldEmitCFI) 178 Asm->OutStreamer->emitCFIEndProc(); 179 } 180