1//===-- AsmPrinterDwarf.cpp - AsmPrinter Dwarf Support --------------------===//
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 implements the Dwarf emissions parts of AsmPrinter.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/ADT/Twine.h"
14#include "llvm/BinaryFormat/Dwarf.h"
15#include "llvm/CodeGen/AsmPrinter.h"
16#include "llvm/CodeGen/DIE.h"
17#include "llvm/CodeGen/MachineFunction.h"
18#include "llvm/IR/DataLayout.h"
19#include "llvm/MC/MCAsmInfo.h"
20#include "llvm/MC/MCDwarf.h"
21#include "llvm/MC/MCSection.h"
22#include "llvm/MC/MCStreamer.h"
23#include "llvm/MC/MCSymbol.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/Target/TargetLoweringObjectFile.h"
26#include <cstdint>
27using namespace llvm;
28
29#define DEBUG_TYPE "asm-printer"
30
31//===----------------------------------------------------------------------===//
32// Dwarf Emission Helper Routines
33//===----------------------------------------------------------------------===//
34
35static const char *DecodeDWARFEncoding(unsigned Encoding) {
36 switch (Encoding) {
37 case dwarf::DW_EH_PE_absptr:
38 return "absptr";
39 case dwarf::DW_EH_PE_omit:
40 return "omit";
41 case dwarf::DW_EH_PE_pcrel:
42 return "pcrel";
43 case dwarf::DW_EH_PE_uleb128:
44 return "uleb128";
45 case dwarf::DW_EH_PE_sleb128:
46 return "sleb128";
47 case dwarf::DW_EH_PE_udata4:
48 return "udata4";
49 case dwarf::DW_EH_PE_udata8:
50 return "udata8";
51 case dwarf::DW_EH_PE_sdata4:
52 return "sdata4";
53 case dwarf::DW_EH_PE_sdata8:
54 return "sdata8";
55 case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata4:
56 return "pcrel udata4";
57 case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4:
58 return "pcrel sdata4";
59 case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8:
60 return "pcrel udata8";
61 case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8:
62 return "pcrel sdata8";
63 case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata4
64 :
65 return "indirect pcrel udata4";
66 case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4
67 :
68 return "indirect pcrel sdata4";
69 case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8
70 :
71 return "indirect pcrel udata8";
72 case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8
73 :
74 return "indirect pcrel sdata8";
75 case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_datarel |
76 dwarf::DW_EH_PE_sdata4:
77 return "indirect datarel sdata4";
78 case dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_datarel |
79 dwarf::DW_EH_PE_sdata8:
80 return "indirect datarel sdata8";
81 }
82
83 return "<unknown encoding>";
84}
85
86/// EmitEncodingByte - Emit a .byte 42 directive that corresponds to an
87/// encoding. If verbose assembly output is enabled, we output comments
88/// describing the encoding. Desc is an optional string saying what the
89/// encoding is specifying (e.g. "LSDA").
90void AsmPrinter::emitEncodingByte(unsigned Val, const char *Desc) const {
91 if (isVerbose()) {
92 if (Desc)
93 OutStreamer->AddComment(T: Twine(Desc) + " Encoding = " +
94 Twine(DecodeDWARFEncoding(Encoding: Val)));
95 else
96 OutStreamer->AddComment(T: Twine("Encoding = ") + DecodeDWARFEncoding(Encoding: Val));
97 }
98
99 OutStreamer->emitIntValue(Value: Val, Size: 1);
100}
101
102/// GetSizeOfEncodedValue - Return the size of the encoding in bytes.
103unsigned AsmPrinter::GetSizeOfEncodedValue(unsigned Encoding) const {
104 if (Encoding == dwarf::DW_EH_PE_omit)
105 return 0;
106
107 switch (Encoding & 0x07) {
108 default:
109 llvm_unreachable("Invalid encoded value.");
110 case dwarf::DW_EH_PE_absptr:
111 return MAI->getCodePointerSize();
112 case dwarf::DW_EH_PE_udata2:
113 return 2;
114 case dwarf::DW_EH_PE_udata4:
115 return 4;
116 case dwarf::DW_EH_PE_udata8:
117 return 8;
118 }
119}
120
121void AsmPrinter::emitTTypeReference(const GlobalValue *GV, unsigned Encoding) {
122 if (GV) {
123 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
124
125 const MCExpr *Exp =
126 TLOF.getTTypeGlobalReference(GV, Encoding, TM, MMI, Streamer&: *OutStreamer);
127 OutStreamer->emitValue(Value: Exp, Size: GetSizeOfEncodedValue(Encoding));
128 } else
129 OutStreamer->emitIntValue(Value: 0, Size: GetSizeOfEncodedValue(Encoding));
130}
131
132void AsmPrinter::emitDwarfSymbolReference(const MCSymbol *Label,
133 bool ForceOffset) const {
134 if (!ForceOffset) {
135 // On COFF targets, we have to emit the special .secrel32 directive.
136 if (MAI->needsDwarfSectionOffsetDirective()) {
137 assert(!isDwarf64() &&
138 "emitting DWARF64 is not implemented for COFF targets");
139 OutStreamer->emitCOFFSecRel32(Symbol: Label, /*Offset=*/0);
140 return;
141 }
142
143 // If the format uses relocations with dwarf, refer to the symbol directly.
144 if (doesDwarfUseRelocationsAcrossSections()) {
145 OutStreamer->emitSymbolValue(Sym: Label, Size: getDwarfOffsetByteSize());
146 return;
147 }
148 }
149
150 // Otherwise, emit it as a label difference from the start of the section.
151 emitLabelDifference(Hi: Label, Lo: Label->getSection().getBeginSymbol(),
152 Size: getDwarfOffsetByteSize());
153}
154
155void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntry S) const {
156 if (doesDwarfUseRelocationsAcrossSections()) {
157 assert(S.Symbol && "No symbol available");
158 emitDwarfSymbolReference(Label: S.Symbol);
159 return;
160 }
161
162 // Just emit the offset directly; no need for symbol math.
163 OutStreamer->emitIntValue(Value: S.Offset, Size: getDwarfOffsetByteSize());
164}
165
166void AsmPrinter::emitDwarfOffset(const MCSymbol *Label, uint64_t Offset) const {
167 emitLabelPlusOffset(Label, Offset, Size: getDwarfOffsetByteSize());
168}
169
170void AsmPrinter::emitDwarfLengthOrOffset(uint64_t Value) const {
171 assert(isDwarf64() || Value <= UINT32_MAX);
172 OutStreamer->emitIntValue(Value, Size: getDwarfOffsetByteSize());
173}
174
175void AsmPrinter::emitDwarfUnitLength(uint64_t Length,
176 const Twine &Comment) const {
177 OutStreamer->emitDwarfUnitLength(Length, Comment);
178}
179
180MCSymbol *AsmPrinter::emitDwarfUnitLength(const Twine &Prefix,
181 const Twine &Comment) const {
182 return OutStreamer->emitDwarfUnitLength(Prefix, Comment);
183}
184
185void AsmPrinter::emitCallSiteOffset(const MCSymbol *Hi, const MCSymbol *Lo,
186 unsigned Encoding) const {
187 // The least significant 3 bits specify the width of the encoding
188 if ((Encoding & 0x7) == dwarf::DW_EH_PE_uleb128)
189 emitLabelDifferenceAsULEB128(Hi, Lo);
190 else
191 emitLabelDifference(Hi, Lo, Size: GetSizeOfEncodedValue(Encoding));
192}
193
194void AsmPrinter::emitCallSiteValue(uint64_t Value, unsigned Encoding) const {
195 // The least significant 3 bits specify the width of the encoding
196 if ((Encoding & 0x7) == dwarf::DW_EH_PE_uleb128)
197 emitULEB128(Value);
198 else
199 OutStreamer->emitIntValue(Value, Size: GetSizeOfEncodedValue(Encoding));
200}
201
202//===----------------------------------------------------------------------===//
203// Dwarf Lowering Routines
204//===----------------------------------------------------------------------===//
205
206void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
207 SMLoc Loc = Inst.getLoc();
208 switch (Inst.getOperation()) {
209 default:
210 llvm_unreachable("Unexpected instruction");
211 case MCCFIInstruction::OpDefCfaOffset:
212 OutStreamer->emitCFIDefCfaOffset(Offset: Inst.getOffset(), Loc);
213 break;
214 case MCCFIInstruction::OpAdjustCfaOffset:
215 OutStreamer->emitCFIAdjustCfaOffset(Adjustment: Inst.getOffset(), Loc);
216 break;
217 case MCCFIInstruction::OpDefCfa:
218 OutStreamer->emitCFIDefCfa(Register: Inst.getRegister(), Offset: Inst.getOffset(), Loc);
219 break;
220 case MCCFIInstruction::OpDefCfaRegister:
221 OutStreamer->emitCFIDefCfaRegister(Register: Inst.getRegister(), Loc);
222 break;
223 case MCCFIInstruction::OpLLVMDefAspaceCfa:
224 OutStreamer->emitCFILLVMDefAspaceCfa(Register: Inst.getRegister(), Offset: Inst.getOffset(),
225 AddressSpace: Inst.getAddressSpace(), Loc);
226 break;
227 case MCCFIInstruction::OpOffset:
228 OutStreamer->emitCFIOffset(Register: Inst.getRegister(), Offset: Inst.getOffset(), Loc);
229 break;
230 case MCCFIInstruction::OpRegister:
231 OutStreamer->emitCFIRegister(Register1: Inst.getRegister(), Register2: Inst.getRegister2(), Loc);
232 break;
233 case MCCFIInstruction::OpWindowSave:
234 OutStreamer->emitCFIWindowSave(Loc);
235 break;
236 case MCCFIInstruction::OpNegateRAState:
237 OutStreamer->emitCFINegateRAState(Loc);
238 break;
239 case MCCFIInstruction::OpSameValue:
240 OutStreamer->emitCFISameValue(Register: Inst.getRegister(), Loc);
241 break;
242 case MCCFIInstruction::OpGnuArgsSize:
243 OutStreamer->emitCFIGnuArgsSize(Size: Inst.getOffset(), Loc);
244 break;
245 case MCCFIInstruction::OpEscape:
246 OutStreamer->AddComment(T: Inst.getComment());
247 OutStreamer->emitCFIEscape(Values: Inst.getValues(), Loc);
248 break;
249 case MCCFIInstruction::OpRestore:
250 OutStreamer->emitCFIRestore(Register: Inst.getRegister(), Loc);
251 break;
252 case MCCFIInstruction::OpUndefined:
253 OutStreamer->emitCFIUndefined(Register: Inst.getRegister(), Loc);
254 break;
255 case MCCFIInstruction::OpRememberState:
256 OutStreamer->emitCFIRememberState(Loc);
257 break;
258 case MCCFIInstruction::OpRestoreState:
259 OutStreamer->emitCFIRestoreState(Loc);
260 break;
261 }
262}
263
264void AsmPrinter::emitDwarfDIE(const DIE &Die) const {
265 // Emit the code (index) for the abbreviation.
266 if (isVerbose())
267 OutStreamer->AddComment(T: "Abbrev [" + Twine(Die.getAbbrevNumber()) + "] 0x" +
268 Twine::utohexstr(Val: Die.getOffset()) + ":0x" +
269 Twine::utohexstr(Val: Die.getSize()) + " " +
270 dwarf::TagString(Tag: Die.getTag()));
271 emitULEB128(Value: Die.getAbbrevNumber());
272
273 // Emit the DIE attribute values.
274 for (const auto &V : Die.values()) {
275 dwarf::Attribute Attr = V.getAttribute();
276 assert(V.getForm() && "Too many attributes for DIE (check abbreviation)");
277
278 if (isVerbose()) {
279 OutStreamer->AddComment(T: dwarf::AttributeString(Attribute: Attr));
280 if (Attr == dwarf::DW_AT_accessibility)
281 OutStreamer->AddComment(
282 T: dwarf::AccessibilityString(Access: V.getDIEInteger().getValue()));
283 }
284
285 // Emit an attribute using the defined form.
286 V.emitValue(AP: this);
287 }
288
289 // Emit the DIE children if any.
290 if (Die.hasChildren()) {
291 for (const auto &Child : Die.children())
292 emitDwarfDIE(Die: Child);
293
294 OutStreamer->AddComment(T: "End Of Children Mark");
295 emitInt8(Value: 0);
296 }
297}
298
299void AsmPrinter::emitDwarfAbbrev(const DIEAbbrev &Abbrev) const {
300 // Emit the abbreviations code (base 1 index.)
301 emitULEB128(Value: Abbrev.getNumber(), Desc: "Abbreviation Code");
302
303 // Emit the abbreviations data.
304 Abbrev.Emit(AP: this);
305}
306