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 | |