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 } 55 Personalities.clear(); 56 } 57 58 void DwarfCFIException::beginFunction(const MachineFunction *MF) { 59 shouldEmitPersonality = shouldEmitLSDA = false; 60 const Function &F = MF->getFunction(); 61 62 // If any landing pads survive, we need an EH table. 63 bool hasLandingPads = !MF->getLandingPads().empty(); 64 65 // See if we need frame move info. 66 bool shouldEmitMoves = 67 Asm->getFunctionCFISectionType(*MF) != AsmPrinter::CFISection::None; 68 69 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 70 unsigned PerEncoding = TLOF.getPersonalityEncoding(); 71 const GlobalValue *Per = nullptr; 72 if (F.hasPersonalityFn()) 73 Per = dyn_cast<GlobalValue>(F.getPersonalityFn()->stripPointerCasts()); 74 75 // Emit a personality function even when there are no landing pads 76 forceEmitPersonality = 77 // ...if a personality function is explicitly specified 78 F.hasPersonalityFn() && 79 // ... and it's not known to be a noop in the absence of invokes 80 !isNoOpWithoutInvoke(classifyEHPersonality(Per)) && 81 // ... and we're not explicitly asked not to emit it 82 F.needsUnwindTableEntry(); 83 84 shouldEmitPersonality = 85 (forceEmitPersonality || 86 (hasLandingPads && PerEncoding != dwarf::DW_EH_PE_omit)) && 87 Per; 88 89 unsigned LSDAEncoding = TLOF.getLSDAEncoding(); 90 shouldEmitLSDA = shouldEmitPersonality && 91 LSDAEncoding != dwarf::DW_EH_PE_omit; 92 93 const MCAsmInfo &MAI = *MF->getContext().getAsmInfo(); 94 if (MAI.getExceptionHandlingType() != ExceptionHandling::None) 95 shouldEmitCFI = 96 MAI.usesCFIForEH() && (shouldEmitPersonality || shouldEmitMoves); 97 else 98 shouldEmitCFI = Asm->usesCFIWithoutEH() && shouldEmitMoves; 99 } 100 101 void DwarfCFIException::beginBasicBlockSection(const MachineBasicBlock &MBB) { 102 if (!shouldEmitCFI) 103 return; 104 105 if (!hasEmittedCFISections) { 106 AsmPrinter::CFISection CFISecType = Asm->getModuleCFISectionType(); 107 // If we don't say anything it implies `.cfi_sections .eh_frame`, so we 108 // chose not to be verbose in that case. And with `ForceDwarfFrameSection`, 109 // we should always emit .debug_frame. 110 if (CFISecType == AsmPrinter::CFISection::Debug || 111 Asm->TM.Options.ForceDwarfFrameSection) 112 Asm->OutStreamer->emitCFISections( 113 CFISecType == AsmPrinter::CFISection::EH, true); 114 hasEmittedCFISections = true; 115 } 116 117 Asm->OutStreamer->emitCFIStartProc(/*IsSimple=*/false); 118 119 // Indicate personality routine, if any. 120 if (!shouldEmitPersonality) 121 return; 122 123 auto &F = MBB.getParent()->getFunction(); 124 auto *P = dyn_cast<GlobalValue>(F.getPersonalityFn()->stripPointerCasts()); 125 assert(P && "Expected personality function"); 126 // Record the personality function. 127 addPersonality(P); 128 129 const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); 130 unsigned PerEncoding = TLOF.getPersonalityEncoding(); 131 const MCSymbol *Sym = TLOF.getCFIPersonalitySymbol(P, Asm->TM, MMI); 132 Asm->OutStreamer->emitCFIPersonality(Sym, PerEncoding); 133 134 // Provide LSDA information. 135 if (shouldEmitLSDA) 136 Asm->OutStreamer->emitCFILsda(Asm->getMBBExceptionSym(MBB), 137 TLOF.getLSDAEncoding()); 138 } 139 140 void DwarfCFIException::endBasicBlockSection(const MachineBasicBlock &MBB) { 141 if (shouldEmitCFI) 142 Asm->OutStreamer->emitCFIEndProc(); 143 } 144 145 /// endFunction - Gather and emit post-function exception information. 146 /// 147 void DwarfCFIException::endFunction(const MachineFunction *MF) { 148 if (!shouldEmitPersonality) 149 return; 150 151 emitExceptionTable(); 152 } 153