Add a possibility to switch between CFI directives- and table-based frame description...
[oota-llvm.git] / lib / CodeGen / AsmPrinter / DwarfTableException.cpp
1 //===-- CodeGen/AsmPrinter/DwarfTableException.cpp - Dwarf Exception Impl --==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains support for writing DWARF exception info into asm files.
11 // The implementation emits all the necessary tables "by hands".
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "DwarfException.h"
16 #include "llvm/Module.h"
17 #include "llvm/CodeGen/AsmPrinter.h"
18 #include "llvm/CodeGen/MachineModuleInfo.h"
19 #include "llvm/CodeGen/MachineFrameInfo.h"
20 #include "llvm/CodeGen/MachineFunction.h"
21 #include "llvm/CodeGen/MachineLocation.h"
22 #include "llvm/MC/MCAsmInfo.h"
23 #include "llvm/MC/MCContext.h"
24 #include "llvm/MC/MCExpr.h"
25 #include "llvm/MC/MCSection.h"
26 #include "llvm/MC/MCStreamer.h"
27 #include "llvm/MC/MCSymbol.h"
28 #include "llvm/Target/Mangler.h"
29 #include "llvm/Target/TargetData.h"
30 #include "llvm/Target/TargetFrameLowering.h"
31 #include "llvm/Target/TargetLoweringObjectFile.h"
32 #include "llvm/Target/TargetMachine.h"
33 #include "llvm/Target/TargetOptions.h"
34 #include "llvm/Target/TargetRegisterInfo.h"
35 #include "llvm/Support/Dwarf.h"
36 #include "llvm/Support/FormattedStream.h"
37 #include "llvm/ADT/SmallString.h"
38 #include "llvm/ADT/StringExtras.h"
39 #include "llvm/ADT/Twine.h"
40 using namespace llvm;
41
42 DwarfTableException::DwarfTableException(AsmPrinter *A)
43   :  DwarfException(A),
44      shouldEmitTable(false), shouldEmitMoves(false),
45      shouldEmitTableModule(false), shouldEmitMovesModule(false) {}
46
47 DwarfTableException::~DwarfTableException() {}
48
49 /// EmitCIE - Emit a Common Information Entry (CIE). This holds information that
50 /// is shared among many Frame Description Entries.  There is at least one CIE
51 /// in every non-empty .debug_frame section.
52 void DwarfTableException::EmitCIE(const Function *PersonalityFn, unsigned Index) {
53   // Size and sign of stack growth.
54   int stackGrowth = Asm->getTargetData().getPointerSize();
55   if (Asm->TM.getFrameLowering()->getStackGrowthDirection() ==
56       TargetFrameLowering::StackGrowsDown)
57     stackGrowth *= -1;
58
59   const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
60
61   // Begin eh frame section.
62   Asm->OutStreamer.SwitchSection(TLOF.getEHFrameSection());
63
64   MCSymbol *EHFrameSym;
65   if (TLOF.isFunctionEHFrameSymbolPrivate())
66     EHFrameSym = Asm->GetTempSymbol("EH_frame", Index);
67   else
68     EHFrameSym = Asm->OutContext.GetOrCreateSymbol(Twine("EH_frame") +
69                                                    Twine(Index));
70   Asm->OutStreamer.EmitLabel(EHFrameSym);
71
72   Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("section_eh_frame", Index));
73
74   // Define base labels.
75   Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_common", Index));
76
77   // Define the eh frame length.
78   Asm->OutStreamer.AddComment("Length of Common Information Entry");
79   Asm->EmitLabelDifference(Asm->GetTempSymbol("eh_frame_common_end", Index),
80                            Asm->GetTempSymbol("eh_frame_common_begin", Index),
81                            4);
82
83   // EH frame header.
84   Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_common_begin",Index));
85   Asm->OutStreamer.AddComment("CIE Identifier Tag");
86   Asm->OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/);
87   Asm->OutStreamer.AddComment("DW_CIE_VERSION");
88   Asm->OutStreamer.EmitIntValue(dwarf::DW_CIE_VERSION, 1/*size*/, 0/*addr*/);
89
90   // The personality presence indicates that language specific information will
91   // show up in the eh frame.  Find out how we are supposed to lower the
92   // personality function reference:
93
94   unsigned LSDAEncoding = TLOF.getLSDAEncoding();
95   unsigned FDEEncoding = TLOF.getFDEEncoding();
96   unsigned PerEncoding = TLOF.getPersonalityEncoding();
97
98   char Augmentation[6] = { 0 };
99   unsigned AugmentationSize = 0;
100   char *APtr = Augmentation + 1;
101
102   if (PersonalityFn) {
103     // There is a personality function.
104     *APtr++ = 'P';
105     AugmentationSize += 1 + Asm->GetSizeOfEncodedValue(PerEncoding);
106   }
107
108   if (UsesLSDA[Index]) {
109     // An LSDA pointer is in the FDE augmentation.
110     *APtr++ = 'L';
111     ++AugmentationSize;
112   }
113
114   if (FDEEncoding != dwarf::DW_EH_PE_absptr) {
115     // A non-default pointer encoding for the FDE.
116     *APtr++ = 'R';
117     ++AugmentationSize;
118   }
119
120   if (APtr != Augmentation + 1)
121     Augmentation[0] = 'z';
122
123   Asm->OutStreamer.AddComment("CIE Augmentation");
124   Asm->OutStreamer.EmitBytes(StringRef(Augmentation, strlen(Augmentation)+1),0);
125
126   // Round out reader.
127   Asm->EmitULEB128(1, "CIE Code Alignment Factor");
128   Asm->EmitSLEB128(stackGrowth, "CIE Data Alignment Factor");
129   Asm->OutStreamer.AddComment("CIE Return Address Column");
130
131   const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo();
132   const TargetFrameLowering *TFI = Asm->TM.getFrameLowering();
133   Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), true));
134
135   if (Augmentation[0]) {
136     Asm->EmitULEB128(AugmentationSize, "Augmentation Size");
137
138     // If there is a personality, we need to indicate the function's location.
139     if (PersonalityFn) {
140       Asm->EmitEncodingByte(PerEncoding, "Personality");
141       Asm->OutStreamer.AddComment("Personality");
142       Asm->EmitReference(PersonalityFn, PerEncoding);
143     }
144     if (UsesLSDA[Index])
145       Asm->EmitEncodingByte(LSDAEncoding, "LSDA");
146     if (FDEEncoding != dwarf::DW_EH_PE_absptr)
147       Asm->EmitEncodingByte(FDEEncoding, "FDE");
148   }
149
150   // Indicate locations of general callee saved registers in frame.
151   std::vector<MachineMove> Moves;
152   TFI->getInitialFrameState(Moves);
153   Asm->EmitFrameMoves(Moves, 0, true);
154
155   // On Darwin the linker honors the alignment of eh_frame, which means it must
156   // be 8-byte on 64-bit targets to match what gcc does.  Otherwise you get
157   // holes which confuse readers of eh_frame.
158   Asm->EmitAlignment(Asm->getTargetData().getPointerSize() == 4 ? 2 : 3);
159   Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_common_end", Index));
160 }
161
162 /// EmitFDE - Emit the Frame Description Entry (FDE) for the function.
163 void DwarfTableException::EmitFDE(const FunctionEHFrameInfo &EHFrameInfo) {
164   assert(!EHFrameInfo.function->hasAvailableExternallyLinkage() &&
165          "Should not emit 'available externally' functions at all");
166
167   const Function *TheFunc = EHFrameInfo.function;
168   const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
169
170   unsigned LSDAEncoding = TLOF.getLSDAEncoding();
171   unsigned FDEEncoding = TLOF.getFDEEncoding();
172
173   Asm->OutStreamer.SwitchSection(TLOF.getEHFrameSection());
174
175   // Externally visible entry into the functions eh frame info. If the
176   // corresponding function is static, this should not be externally visible.
177   if (!TheFunc->hasLocalLinkage() && TLOF.isFunctionEHSymbolGlobal())
178     Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym,MCSA_Global);
179
180   // If corresponding function is weak definition, this should be too.
181   if (TheFunc->isWeakForLinker() && Asm->MAI->getWeakDefDirective())
182     Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym,
183                                          MCSA_WeakDefinition);
184
185   // If corresponding function is hidden, this should be too.
186   if (TheFunc->hasHiddenVisibility())
187     if (MCSymbolAttr HiddenAttr = Asm->MAI->getHiddenVisibilityAttr())
188       Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym,
189                                            HiddenAttr);
190
191   // If there are no calls then you can't unwind.  This may mean we can omit the
192   // EH Frame, but some environments do not handle weak absolute symbols. If
193   // UnwindTablesMandatory is set we cannot do this optimization; the unwind
194   // info is to be available for non-EH uses.
195   if (!EHFrameInfo.adjustsStack && !UnwindTablesMandatory &&
196       (!TheFunc->isWeakForLinker() ||
197        !Asm->MAI->getWeakDefDirective() ||
198        TLOF.getSupportsWeakOmittedEHFrame())) {
199     Asm->OutStreamer.EmitAssignment(EHFrameInfo.FunctionEHSym,
200                                     MCConstantExpr::Create(0, Asm->OutContext));
201     // This name has no connection to the function, so it might get
202     // dead-stripped when the function is not, erroneously.  Prohibit
203     // dead-stripping unconditionally.
204     if (Asm->MAI->hasNoDeadStrip())
205       Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym,
206                                            MCSA_NoDeadStrip);
207   } else {
208     Asm->OutStreamer.EmitLabel(EHFrameInfo.FunctionEHSym);
209
210     // EH frame header.
211     Asm->OutStreamer.AddComment("Length of Frame Information Entry");
212     Asm->EmitLabelDifference(
213                 Asm->GetTempSymbol("eh_frame_end", EHFrameInfo.Number),
214                 Asm->GetTempSymbol("eh_frame_begin", EHFrameInfo.Number), 4);
215
216     Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_begin",
217                                                   EHFrameInfo.Number));
218
219     Asm->OutStreamer.AddComment("FDE CIE offset");
220     Asm->EmitLabelDifference(
221                        Asm->GetTempSymbol("eh_frame_begin", EHFrameInfo.Number),
222                        Asm->GetTempSymbol("eh_frame_common",
223                                           EHFrameInfo.PersonalityIndex), 4);
224
225     MCSymbol *EHFuncBeginSym =
226       Asm->GetTempSymbol("eh_func_begin", EHFrameInfo.Number);
227
228     Asm->OutStreamer.AddComment("FDE initial location");
229     Asm->EmitReference(EHFuncBeginSym, FDEEncoding);
230
231     Asm->OutStreamer.AddComment("FDE address range");
232     Asm->EmitLabelDifference(Asm->GetTempSymbol("eh_func_end",
233                                                 EHFrameInfo.Number),
234                              EHFuncBeginSym,
235                              Asm->GetSizeOfEncodedValue(FDEEncoding));
236
237     // If there is a personality and landing pads then point to the language
238     // specific data area in the exception table.
239     if (MMI->getPersonalities()[0] != NULL) {
240       unsigned Size = Asm->GetSizeOfEncodedValue(LSDAEncoding);
241
242       Asm->EmitULEB128(Size, "Augmentation size");
243       Asm->OutStreamer.AddComment("Language Specific Data Area");
244       if (EHFrameInfo.hasLandingPads)
245         Asm->EmitReference(Asm->GetTempSymbol("exception", EHFrameInfo.Number),
246                            LSDAEncoding);
247       else
248         Asm->OutStreamer.EmitIntValue(0, Size/*size*/, 0/*addrspace*/);
249
250     } else {
251       Asm->EmitULEB128(0, "Augmentation size");
252     }
253
254     // Indicate locations of function specific callee saved registers in frame.
255     Asm->EmitFrameMoves(EHFrameInfo.Moves, EHFuncBeginSym, true);
256
257     // On Darwin the linker honors the alignment of eh_frame, which means it
258     // must be 8-byte on 64-bit targets to match what gcc does.  Otherwise you
259     // get holes which confuse readers of eh_frame.
260     Asm->EmitAlignment(Asm->getTargetData().getPointerSize() == 4 ? 2 : 3);
261     Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_end",
262                                                   EHFrameInfo.Number));
263
264     // If the function is marked used, this table should be also.  We cannot
265     // make the mark unconditional in this case, since retaining the table also
266     // retains the function in this case, and there is code around that depends
267     // on unused functions (calling undefined externals) being dead-stripped to
268     // link correctly.  Yes, there really is.
269     if (MMI->isUsedFunction(EHFrameInfo.function))
270       if (Asm->MAI->hasNoDeadStrip())
271         Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym,
272                                              MCSA_NoDeadStrip);
273   }
274   Asm->OutStreamer.AddBlankLine();
275 }
276
277 /// EndModule - Emit all exception information that should come after the
278 /// content.
279 void DwarfTableException::EndModule() {
280   if (!Asm->MAI->isExceptionHandlingDwarf())
281     return;
282
283   if (!shouldEmitMovesModule && !shouldEmitTableModule)
284     return;
285
286   const std::vector<const Function*> &Personalities = MMI->getPersonalities();
287
288   for (unsigned I = 0, E = Personalities.size(); I < E; ++I)
289     EmitCIE(Personalities[I], I);
290
291   for (std::vector<FunctionEHFrameInfo>::iterator
292          I = EHFrames.begin(), E = EHFrames.end(); I != E; ++I)
293     EmitFDE(*I);
294 }
295
296 /// BeginFunction - Gather pre-function exception information. Assumes it's
297 /// being emitted immediately after the function entry point.
298 void DwarfTableException::BeginFunction(const MachineFunction *MF) {
299   shouldEmitTable = shouldEmitMoves = false;
300
301   // If any landing pads survive, we need an EH table.
302   shouldEmitTable = !MMI->getLandingPads().empty();
303
304   // See if we need frame move info.
305   shouldEmitMoves =
306     !Asm->MF->getFunction()->doesNotThrow() || UnwindTablesMandatory;
307
308   if (shouldEmitMoves || shouldEmitTable)
309     // Assumes in correct section after the entry point.
310     Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin",
311                                                   Asm->getFunctionNumber()));
312
313   shouldEmitTableModule |= shouldEmitTable;
314   shouldEmitMovesModule |= shouldEmitMoves;
315 }
316
317 /// EndFunction - Gather and emit post-function exception information.
318 ///
319 void DwarfTableException::EndFunction() {
320   if (!shouldEmitMoves && !shouldEmitTable) return;
321
322   Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_end",
323                                                 Asm->getFunctionNumber()));
324
325   // Record if this personality index uses a landing pad.
326   bool HasLandingPad = !MMI->getLandingPads().empty();
327   UsesLSDA[MMI->getPersonalityIndex()] |= HasLandingPad;
328
329   // Map all labels and get rid of any dead landing pads.
330   MMI->TidyLandingPads();
331
332   if (HasLandingPad)
333     EmitExceptionTable();
334
335   const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering();
336   MCSymbol *FunctionEHSym =
337     Asm->GetSymbolWithGlobalValueBase(Asm->MF->getFunction(), ".eh",
338                                       TLOF.isFunctionEHFrameSymbolPrivate());
339
340   // Save EH frame information
341   EHFrames.
342     push_back(FunctionEHFrameInfo(FunctionEHSym,
343                                   Asm->getFunctionNumber(),
344                                   MMI->getPersonalityIndex(),
345                                   Asm->MF->getFrameInfo()->adjustsStack(),
346                                   !MMI->getLandingPads().empty(),
347                                   MMI->getFrameMoves(),
348                                   Asm->MF->getFunction()));
349 }