| 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(Range&: Personalities, Element: Personality)) |
| 33 | Personalities.push_back(x: 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(GV: Personality); |
| 53 | TLOF.emitPersonalityValue(Streamer&: *Asm->OutStreamer, TM: Asm->getDataLayout(), Sym, |
| 54 | MMI: 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: *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>(Val: 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(Pers: classifyEHPersonality(Pers: 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 | EH: CFISecType == AsmPrinter::CFISection::EH, Debug: 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>(Val: F.getPersonalityFn()->stripPointerCasts()); |
| 126 | assert(P && "Expected personality function" ); |
| 127 | // Record the personality function. |
| 128 | addPersonality(Personality: P); |
| 129 | |
| 130 | const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); |
| 131 | unsigned PerEncoding = TLOF.getPersonalityEncoding(); |
| 132 | const MCSymbol *Sym = TLOF.getCFIPersonalitySymbol(GV: P, TM: Asm->TM, MMI); |
| 133 | Asm->OutStreamer->emitCFIPersonality(Sym, Encoding: PerEncoding); |
| 134 | |
| 135 | // Provide LSDA information. |
| 136 | if (shouldEmitLSDA) |
| 137 | Asm->OutStreamer->emitCFILsda(Sym: Asm->getMBBExceptionSym(MBB), |
| 138 | Encoding: 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 | |