1 //===- MCDwarf.h - Machine Code Dwarf support -------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains the declaration of the MCDwarfFile to support the dwarf
10 // .file directive and the .loc directive.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_MC_MCDWARF_H
15 #define LLVM_MC_MCDWARF_H
17 #include "llvm/ADT/MapVector.h"
18 #include "llvm/ADT/Optional.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/StringMap.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/MC/MCSection.h"
23 #include "llvm/Support/Error.h"
24 #include "llvm/Support/MD5.h"
33 template <typename T> class ArrayRef;
37 class MCObjectStreamer;
44 /// Instances of this class represent the name of the dwarf .file directive and
45 /// its associated dwarf file number in the MC file. MCDwarfFile's are created
46 /// and uniqued by the MCContext class. In Dwarf 4 file numbers start from 1;
47 /// i.e. the entry with file number 1 is the first element in the vector of
48 /// DwarfFiles and there is no MCDwarfFile with file number 0. In Dwarf 5 file
49 /// numbers start from 0, with the MCDwarfFile with file number 0 being the
50 /// primary source file, and file numbers correspond to their index in the
53 // The base name of the file without its directory path.
56 // The index into the list of directory names for this file name.
59 /// The MD5 checksum, if there is one. Non-owning pointer to data allocated
61 Optional<MD5::MD5Result> Checksum;
63 /// The source code of the file. Non-owning reference to data allocated in
65 Optional<StringRef> Source;
68 /// Instances of this class represent the information from a
69 /// dwarf .loc directive.
74 // Flags (see #define's below)
77 uint32_t Discriminator;
79 // Flag that indicates the initial value of the is_stmt_start flag.
80 #define DWARF2_LINE_DEFAULT_IS_STMT 1
82 #define DWARF2_FLAG_IS_STMT (1 << 0)
83 #define DWARF2_FLAG_BASIC_BLOCK (1 << 1)
84 #define DWARF2_FLAG_PROLOGUE_END (1 << 2)
85 #define DWARF2_FLAG_EPILOGUE_BEGIN (1 << 3)
87 private: // MCContext manages these
88 friend class MCContext;
89 friend class MCDwarfLineEntry;
91 MCDwarfLoc(unsigned fileNum, unsigned line, unsigned column, unsigned flags,
92 unsigned isa, unsigned discriminator)
93 : FileNum(fileNum), Line(line), Column(column), Flags(flags), Isa(isa),
94 Discriminator(discriminator) {}
96 // Allow the default copy constructor and assignment operator to be used
97 // for an MCDwarfLoc object.
100 /// Get the FileNum of this MCDwarfLoc.
101 unsigned getFileNum() const { return FileNum; }
103 /// Get the Line of this MCDwarfLoc.
104 unsigned getLine() const { return Line; }
106 /// Get the Column of this MCDwarfLoc.
107 unsigned getColumn() const { return Column; }
109 /// Get the Flags of this MCDwarfLoc.
110 unsigned getFlags() const { return Flags; }
112 /// Get the Isa of this MCDwarfLoc.
113 unsigned getIsa() const { return Isa; }
115 /// Get the Discriminator of this MCDwarfLoc.
116 unsigned getDiscriminator() const { return Discriminator; }
118 /// Set the FileNum of this MCDwarfLoc.
119 void setFileNum(unsigned fileNum) { FileNum = fileNum; }
121 /// Set the Line of this MCDwarfLoc.
122 void setLine(unsigned line) { Line = line; }
124 /// Set the Column of this MCDwarfLoc.
125 void setColumn(unsigned column) {
126 assert(column <= UINT16_MAX);
130 /// Set the Flags of this MCDwarfLoc.
131 void setFlags(unsigned flags) {
132 assert(flags <= UINT8_MAX);
136 /// Set the Isa of this MCDwarfLoc.
137 void setIsa(unsigned isa) {
138 assert(isa <= UINT8_MAX);
142 /// Set the Discriminator of this MCDwarfLoc.
143 void setDiscriminator(unsigned discriminator) {
144 Discriminator = discriminator;
148 /// Instances of this class represent the line information for
149 /// the dwarf line table entries. Which is created after a machine
150 /// instruction is assembled and uses an address from a temporary label
151 /// created at the current address in the current section and the info from
152 /// the last .loc directive seen as stored in the context.
153 class MCDwarfLineEntry : public MCDwarfLoc {
157 // Allow the default copy constructor and assignment operator to be used
158 // for an MCDwarfLineEntry object.
161 // Constructor to create an MCDwarfLineEntry given a symbol and the dwarf loc.
162 MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc)
163 : MCDwarfLoc(loc), Label(label) {}
165 MCSymbol *getLabel() const { return Label; }
167 // This is called when an instruction is assembled into the specified
168 // section and if there is information from the last .loc directive that
169 // has yet to have a line entry made for it is made.
170 static void Make(MCObjectStreamer *MCOS, MCSection *Section);
173 /// Instances of this class represent the line information for a compile
174 /// unit where machine instructions have been assembled after seeing .loc
175 /// directives. This is the information used to build the dwarf line
176 /// table for a section.
177 class MCLineSection {
179 // Add an entry to this MCLineSection's line entries.
180 void addLineEntry(const MCDwarfLineEntry &LineEntry, MCSection *Sec) {
181 MCLineDivisions[Sec].push_back(LineEntry);
184 using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>;
185 using iterator = MCDwarfLineEntryCollection::iterator;
186 using const_iterator = MCDwarfLineEntryCollection::const_iterator;
187 using MCLineDivisionMap = MapVector<MCSection *, MCDwarfLineEntryCollection>;
190 // A collection of MCDwarfLineEntry for each section.
191 MCLineDivisionMap MCLineDivisions;
194 // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID.
195 const MCLineDivisionMap &getMCLineEntries() const {
196 return MCLineDivisions;
200 struct MCDwarfLineTableParams {
201 /// First special line opcode - leave room for the standard opcodes.
202 /// Note: If you want to change this, you'll have to update the
203 /// "StandardOpcodeLengths" table that is emitted in
205 uint8_t DWARF2LineOpcodeBase = 13;
206 /// Minimum line offset in a special line info. opcode. The value
207 /// -5 was chosen to give a reasonable range of values.
208 int8_t DWARF2LineBase = -5;
209 /// Range of line offsets in a special line info. opcode.
210 uint8_t DWARF2LineRange = 14;
213 struct MCDwarfLineTableHeader {
214 MCSymbol *Label = nullptr;
215 SmallVector<std::string, 3> MCDwarfDirs;
216 SmallVector<MCDwarfFile, 3> MCDwarfFiles;
217 StringMap<unsigned> SourceIdMap;
218 std::string CompilationDir;
219 MCDwarfFile RootFile;
220 bool HasSource = false;
222 bool HasAllMD5 = true;
223 bool HasAnyMD5 = false;
226 MCDwarfLineTableHeader() = default;
228 Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
229 Optional<MD5::MD5Result> Checksum,
230 Optional<StringRef> Source,
231 uint16_t DwarfVersion,
232 unsigned FileNumber = 0);
233 std::pair<MCSymbol *, MCSymbol *>
234 Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
235 Optional<MCDwarfLineStr> &LineStr) const;
236 std::pair<MCSymbol *, MCSymbol *>
237 Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
238 ArrayRef<char> SpecialOpcodeLengths,
239 Optional<MCDwarfLineStr> &LineStr) const;
240 void resetMD5Usage() {
244 void trackMD5Usage(bool MD5Used) {
245 HasAllMD5 &= MD5Used;
246 HasAnyMD5 |= MD5Used;
248 bool isMD5UsageConsistent() const {
249 return MCDwarfFiles.empty() || (HasAllMD5 == HasAnyMD5);
252 void setRootFile(StringRef Directory, StringRef FileName,
253 Optional<MD5::MD5Result> Checksum,
254 Optional<StringRef> Source) {
255 CompilationDir = Directory;
256 RootFile.Name = FileName;
257 RootFile.DirIndex = 0;
258 RootFile.Checksum = Checksum;
259 RootFile.Source = Source;
260 trackMD5Usage(Checksum.hasValue());
261 HasSource = Source.hasValue();
264 void resetFileTable() {
266 MCDwarfFiles.clear();
267 RootFile.Name.clear();
273 void emitV2FileDirTables(MCStreamer *MCOS) const;
274 void emitV5FileDirTables(MCStreamer *MCOS, Optional<MCDwarfLineStr> &LineStr) const;
277 class MCDwarfDwoLineTable {
278 MCDwarfLineTableHeader Header;
279 bool HasSplitLineTable = false;
282 void maybeSetRootFile(StringRef Directory, StringRef FileName,
283 Optional<MD5::MD5Result> Checksum,
284 Optional<StringRef> Source) {
285 if (!Header.RootFile.Name.empty())
287 Header.setRootFile(Directory, FileName, Checksum, Source);
290 unsigned getFile(StringRef Directory, StringRef FileName,
291 Optional<MD5::MD5Result> Checksum, uint16_t DwarfVersion,
292 Optional<StringRef> Source) {
293 HasSplitLineTable = true;
294 return cantFail(Header.tryGetFile(Directory, FileName, Checksum, Source,
298 void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params,
299 MCSection *Section) const;
302 class MCDwarfLineTable {
303 MCDwarfLineTableHeader Header;
304 MCLineSection MCLineSections;
307 // This emits the Dwarf file and the line tables for all Compile Units.
308 static void Emit(MCObjectStreamer *MCOS, MCDwarfLineTableParams Params);
310 // This emits the Dwarf file and the line tables for a given Compile Unit.
311 void EmitCU(MCObjectStreamer *MCOS, MCDwarfLineTableParams Params,
312 Optional<MCDwarfLineStr> &LineStr) const;
314 Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
315 Optional<MD5::MD5Result> Checksum,
316 Optional<StringRef> Source,
317 uint16_t DwarfVersion,
318 unsigned FileNumber = 0);
319 unsigned getFile(StringRef &Directory, StringRef &FileName,
320 Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source,
321 uint16_t DwarfVersion, unsigned FileNumber = 0) {
322 return cantFail(tryGetFile(Directory, FileName, Checksum, Source,
323 DwarfVersion, FileNumber));
326 void setRootFile(StringRef Directory, StringRef FileName,
327 Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source) {
328 Header.CompilationDir = Directory;
329 Header.RootFile.Name = FileName;
330 Header.RootFile.DirIndex = 0;
331 Header.RootFile.Checksum = Checksum;
332 Header.RootFile.Source = Source;
333 Header.trackMD5Usage(Checksum.hasValue());
334 Header.HasSource = Source.hasValue();
337 void resetFileTable() { Header.resetFileTable(); }
339 bool hasRootFile() const { return !Header.RootFile.Name.empty(); }
341 const MCDwarfFile &getRootFile() const { return Header.RootFile; }
343 // Report whether MD5 usage has been consistent (all-or-none).
344 bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); }
346 MCSymbol *getLabel() const {
350 void setLabel(MCSymbol *Label) {
351 Header.Label = Label;
354 const SmallVectorImpl<std::string> &getMCDwarfDirs() const {
355 return Header.MCDwarfDirs;
358 SmallVectorImpl<std::string> &getMCDwarfDirs() {
359 return Header.MCDwarfDirs;
362 const SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() const {
363 return Header.MCDwarfFiles;
366 SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() {
367 return Header.MCDwarfFiles;
370 const MCLineSection &getMCLineSections() const {
371 return MCLineSections;
373 MCLineSection &getMCLineSections() {
374 return MCLineSections;
378 class MCDwarfLineAddr {
380 /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas.
381 static void Encode(MCContext &Context, MCDwarfLineTableParams Params,
382 int64_t LineDelta, uint64_t AddrDelta, raw_ostream &OS);
384 /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas using
385 /// fixed length operands.
386 static bool FixedEncode(MCContext &Context,
387 MCDwarfLineTableParams Params,
388 int64_t LineDelta, uint64_t AddrDelta,
389 raw_ostream &OS, uint32_t *Offset, uint32_t *Size);
391 /// Utility function to emit the encoding to a streamer.
392 static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
393 int64_t LineDelta, uint64_t AddrDelta);
396 class MCGenDwarfInfo {
399 // When generating dwarf for assembly source files this emits the Dwarf
402 static void Emit(MCStreamer *MCOS);
405 // When generating dwarf for assembly source files this is the info that is
406 // needed to be gathered for each symbol that will have a dwarf label.
407 class MCGenDwarfLabelEntry {
409 // Name of the symbol without a leading underbar, if any.
411 // The dwarf file number this symbol is in.
413 // The line number this symbol is at.
415 // The low_pc for the dwarf label is taken from this symbol.
419 MCGenDwarfLabelEntry(StringRef name, unsigned fileNumber, unsigned lineNumber,
421 : Name(name), FileNumber(fileNumber), LineNumber(lineNumber),
424 StringRef getName() const { return Name; }
425 unsigned getFileNumber() const { return FileNumber; }
426 unsigned getLineNumber() const { return LineNumber; }
427 MCSymbol *getLabel() const { return Label; }
429 // This is called when label is created when we are generating dwarf for
430 // assembly source files.
431 static void Make(MCSymbol *Symbol, MCStreamer *MCOS, SourceMgr &SrcMgr,
435 class MCCFIInstruction {
464 std::vector<char> Values;
466 MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, StringRef V)
467 : Operation(Op), Label(L), Register(R), Offset(O),
468 Values(V.begin(), V.end()) {
469 assert(Op != OpRegister);
472 MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2)
473 : Operation(Op), Label(L), Register(R1), Register2(R2) {
474 assert(Op == OpRegister);
478 /// .cfi_def_cfa defines a rule for computing CFA as: take address from
479 /// Register and add Offset to it.
480 static MCCFIInstruction createDefCfa(MCSymbol *L, unsigned Register,
482 return MCCFIInstruction(OpDefCfa, L, Register, -Offset, "");
485 /// .cfi_def_cfa_register modifies a rule for computing CFA. From now
486 /// on Register will be used instead of the old one. Offset remains the same.
487 static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register) {
488 return MCCFIInstruction(OpDefCfaRegister, L, Register, 0, "");
491 /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register
492 /// remains the same, but offset is new. Note that it is the absolute offset
493 /// that will be added to a defined register to the compute CFA address.
494 static MCCFIInstruction createDefCfaOffset(MCSymbol *L, int Offset) {
495 return MCCFIInstruction(OpDefCfaOffset, L, 0, -Offset, "");
498 /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but
499 /// Offset is a relative value that is added/subtracted from the previous
501 static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int Adjustment) {
502 return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, "");
505 /// .cfi_offset Previous value of Register is saved at offset Offset
507 static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register,
509 return MCCFIInstruction(OpOffset, L, Register, Offset, "");
512 /// .cfi_rel_offset Previous value of Register is saved at offset
513 /// Offset from the current CFA register. This is transformed to .cfi_offset
514 /// using the known displacement of the CFA register from the CFA.
515 static MCCFIInstruction createRelOffset(MCSymbol *L, unsigned Register,
517 return MCCFIInstruction(OpRelOffset, L, Register, Offset, "");
520 /// .cfi_register Previous value of Register1 is saved in
521 /// register Register2.
522 static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1,
523 unsigned Register2) {
524 return MCCFIInstruction(OpRegister, L, Register1, Register2);
527 /// .cfi_window_save SPARC register window is saved.
528 static MCCFIInstruction createWindowSave(MCSymbol *L) {
529 return MCCFIInstruction(OpWindowSave, L, 0, 0, "");
532 /// .cfi_negate_ra_state AArch64 negate RA state.
533 static MCCFIInstruction createNegateRAState(MCSymbol *L) {
534 return MCCFIInstruction(OpNegateRAState, L, 0, 0, "");
537 /// .cfi_restore says that the rule for Register is now the same as it
538 /// was at the beginning of the function, after all initial instructions added
539 /// by .cfi_startproc were executed.
540 static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register) {
541 return MCCFIInstruction(OpRestore, L, Register, 0, "");
544 /// .cfi_undefined From now on the previous value of Register can't be
545 /// restored anymore.
546 static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register) {
547 return MCCFIInstruction(OpUndefined, L, Register, 0, "");
550 /// .cfi_same_value Current value of Register is the same as in the
551 /// previous frame. I.e., no restoration is needed.
552 static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register) {
553 return MCCFIInstruction(OpSameValue, L, Register, 0, "");
556 /// .cfi_remember_state Save all current rules for all registers.
557 static MCCFIInstruction createRememberState(MCSymbol *L) {
558 return MCCFIInstruction(OpRememberState, L, 0, 0, "");
561 /// .cfi_restore_state Restore the previously saved state.
562 static MCCFIInstruction createRestoreState(MCSymbol *L) {
563 return MCCFIInstruction(OpRestoreState, L, 0, 0, "");
566 /// .cfi_escape Allows the user to add arbitrary bytes to the unwind
568 static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals) {
569 return MCCFIInstruction(OpEscape, L, 0, 0, Vals);
572 /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
573 static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int Size) {
574 return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, "");
577 OpType getOperation() const { return Operation; }
578 MCSymbol *getLabel() const { return Label; }
580 unsigned getRegister() const {
581 assert(Operation == OpDefCfa || Operation == OpOffset ||
582 Operation == OpRestore || Operation == OpUndefined ||
583 Operation == OpSameValue || Operation == OpDefCfaRegister ||
584 Operation == OpRelOffset || Operation == OpRegister);
588 unsigned getRegister2() const {
589 assert(Operation == OpRegister);
593 int getOffset() const {
594 assert(Operation == OpDefCfa || Operation == OpOffset ||
595 Operation == OpRelOffset || Operation == OpDefCfaOffset ||
596 Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize);
600 StringRef getValues() const {
601 assert(Operation == OpEscape);
602 return StringRef(&Values[0], Values.size());
606 struct MCDwarfFrameInfo {
607 MCDwarfFrameInfo() = default;
609 MCSymbol *Begin = nullptr;
610 MCSymbol *End = nullptr;
611 const MCSymbol *Personality = nullptr;
612 const MCSymbol *Lsda = nullptr;
613 std::vector<MCCFIInstruction> Instructions;
614 unsigned CurrentCfaRegister = 0;
615 unsigned PersonalityEncoding = 0;
616 unsigned LsdaEncoding = 0;
617 uint32_t CompactUnwindEncoding = 0;
618 bool IsSignalFrame = false;
619 bool IsSimple = false;
620 unsigned RAReg = static_cast<unsigned>(INT_MAX);
621 bool IsBKeyFrame = false;
624 class MCDwarfFrameEmitter {
627 // This emits the frame info section.
629 static void Emit(MCObjectStreamer &streamer, MCAsmBackend *MAB, bool isEH);
630 static void EmitAdvanceLoc(MCObjectStreamer &Streamer, uint64_t AddrDelta);
631 static void EncodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta,
632 raw_ostream &OS, uint32_t *Offset = nullptr,
633 uint32_t *Size = nullptr);
636 } // end namespace llvm
638 #endif // LLVM_MC_MCDWARF_H