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/IR/Function.h" 19 #include "llvm/MC/MCAsmInfo.h" 20 #include "llvm/MC/MCContext.h" 21 #include "llvm/MC/MCStreamer.h" 22 #include "llvm/Target/TargetLoweringObjectFile.h" 23 #include "llvm/Target/TargetMachine.h" 24 #include "llvm/Target/TargetOptions.h" 25 using namespace llvm; 26 27 DwarfCFIException::DwarfCFIException(AsmPrinter *A) : EHStreamer(A) {} 28 29 DwarfCFIException::~DwarfCFIException() = default; 30 31 void DwarfCFIException::addPersonality(const GlobalValue *Personality) { 32 if (!llvm::is_contained(Personalities, Personality)) 33 Personalities.push_back(Personality); 34 } 35 36 /// endModule - Emit all exception information that should come after the 37 /// content. 38 void DwarfCFIException::endModule() { 39 // SjLj uses this pass and it doesn't need this info. 40 if (!Asm->MAI->usesCFIForEH()) 41 return; 42 43 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 44 45 unsigned PerEncoding = TLOF.getPersonalityEncoding(); 46 47 if ((PerEncoding & 0x80) != dwarf::DW_EH_PE_indirect) 48 return; 49 50 // Emit indirect reference table for all used personality functions 51 for (const GlobalValue *Personality : Personalities) { 52 MCSymbol *Sym = Asm->getSymbol(Personality); 53 TLOF.emitPersonalityValue(*Asm->OutStreamer, Asm->getDataLayout(), Sym, 54 Asm->MMI); 55 } 56 Personalities.clear(); 57 } 58 59 void DwarfCFIException::beginFunction(const MachineFunction *MF) { 60 shouldEmitPersonality = shouldEmitLSDA = false; 61 const Function &F = MF->getFunction(); 62 63 // If any landing pads survive, we need an EH table. 64 bool hasLandingPads = !MF->getLandingPads().empty(); 65 66 // See if we need frame move info. 67 bool shouldEmitMoves = 68 Asm->getFunctionCFISectionType(*MF) != AsmPrinter::CFISection::None; 69 70 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 71 unsigned PerEncoding = TLOF.getPersonalityEncoding(); 72 const GlobalValue *Per = nullptr; 73 if (F.hasPersonalityFn()) 74 Per = dyn_cast<GlobalValue>(F.getPersonalityFn()->stripPointerCasts()); 75 76 // Emit a personality function even when there are no landing pads 77 forceEmitPersonality = 78 // ...if a personality function is explicitly specified 79 F.hasPersonalityFn() && 80 // ... and it's not known to be a noop in the absence of invokes 81 !isNoOpWithoutInvoke(classifyEHPersonality(Per)) && 82 // ... and we're not explicitly asked not to emit it 83 F.needsUnwindTableEntry(); 84 85 shouldEmitPersonality = 86 (forceEmitPersonality || 87 (hasLandingPads && PerEncoding != dwarf::DW_EH_PE_omit)) && 88 Per; 89 90 unsigned LSDAEncoding = TLOF.getLSDAEncoding(); 91 shouldEmitLSDA = shouldEmitPersonality && 92 LSDAEncoding != dwarf::DW_EH_PE_omit; 93 94 const MCAsmInfo &MAI = *MF->getContext().getAsmInfo(); 95 if (MAI.getExceptionHandlingType() != ExceptionHandling::None) 96 shouldEmitCFI = 97 MAI.usesCFIForEH() && (shouldEmitPersonality || shouldEmitMoves); 98 else 99 shouldEmitCFI = Asm->usesCFIWithoutEH() && shouldEmitMoves; 100 } 101 102 void DwarfCFIException::beginBasicBlockSection(const MachineBasicBlock &MBB) { 103 if (!shouldEmitCFI) 104 return; 105 106 if (!hasEmittedCFISections) { 107 AsmPrinter::CFISection CFISecType = Asm->getModuleCFISectionType(); 108 // If we don't say anything it implies `.cfi_sections .eh_frame`, so we 109 // chose not to be verbose in that case. And with `ForceDwarfFrameSection`, 110 // we should always emit .debug_frame. 111 if (CFISecType == AsmPrinter::CFISection::Debug || 112 Asm->TM.Options.ForceDwarfFrameSection) 113 Asm->OutStreamer->emitCFISections( 114 CFISecType == AsmPrinter::CFISection::EH, true); 115 hasEmittedCFISections = true; 116 } 117 118 Asm->OutStreamer->emitCFIStartProc(/*IsSimple=*/false); 119 120 // Indicate personality routine, if any. 121 if (!shouldEmitPersonality) 122 return; 123 124 auto &F = MBB.getParent()->getFunction(); 125 auto *P = dyn_cast<GlobalValue>(F.getPersonalityFn()->stripPointerCasts()); 126 assert(P && "Expected personality function"); 127 // Record the personality function. 128 addPersonality(P); 129 130 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 131 unsigned PerEncoding = TLOF.getPersonalityEncoding(); 132 const MCSymbol *Sym = TLOF.getCFIPersonalitySymbol(P, Asm->TM, MMI); 133 Asm->OutStreamer->emitCFIPersonality(Sym, PerEncoding); 134 135 // Provide LSDA information. 136 if (shouldEmitLSDA) 137 Asm->OutStreamer->emitCFILsda(Asm->getMBBExceptionSym(MBB), 138 TLOF.getLSDAEncoding()); 139 } 140 141 void DwarfCFIException::endBasicBlockSection(const MachineBasicBlock &MBB) { 142 if (shouldEmitCFI) 143 Asm->OutStreamer->emitCFIEndProc(); 144 } 145 146 /// endFunction - Gather and emit post-function exception information. 147 /// 148 void DwarfCFIException::endFunction(const MachineFunction *MF) { 149 if (!shouldEmitPersonality) 150 return; 151 152 emitExceptionTable(); 153 } 154