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;
45 // Emit the common part of the DWARF 5 range/locations list tables header.
46 MCSymbol *emitListsTableHeaderStart(MCStreamer &S);
47 } // namespace mcdwarf
49 /// Instances of this class represent the name of the dwarf .file directive and
50 /// its associated dwarf file number in the MC file. MCDwarfFile's are created
51 /// and uniqued by the MCContext class. In Dwarf 4 file numbers start from 1;
52 /// i.e. the entry with file number 1 is the first element in the vector of
53 /// DwarfFiles and there is no MCDwarfFile with file number 0. In Dwarf 5 file
54 /// numbers start from 0, with the MCDwarfFile with file number 0 being the
55 /// primary source file, and file numbers correspond to their index in the
58 // The base name of the file without its directory path.
61 // The index into the list of directory names for this file name.
62 unsigned DirIndex = 0;
64 /// The MD5 checksum, if there is one. Non-owning pointer to data allocated
66 Optional<MD5::MD5Result> Checksum;
68 /// The source code of the file. Non-owning reference to data allocated in
70 Optional<StringRef> Source;
73 /// Instances of this class represent the information from a
74 /// dwarf .loc directive.
79 // Flags (see #define's below)
82 uint32_t Discriminator;
84 // Flag that indicates the initial value of the is_stmt_start flag.
85 #define DWARF2_LINE_DEFAULT_IS_STMT 1
87 #define DWARF2_FLAG_IS_STMT (1 << 0)
88 #define DWARF2_FLAG_BASIC_BLOCK (1 << 1)
89 #define DWARF2_FLAG_PROLOGUE_END (1 << 2)
90 #define DWARF2_FLAG_EPILOGUE_BEGIN (1 << 3)
92 private: // MCContext manages these
93 friend class MCContext;
94 friend class MCDwarfLineEntry;
96 MCDwarfLoc(unsigned fileNum, unsigned line, unsigned column, unsigned flags,
97 unsigned isa, unsigned discriminator)
98 : FileNum(fileNum), Line(line), Column(column), Flags(flags), Isa(isa),
99 Discriminator(discriminator) {}
101 // Allow the default copy constructor and assignment operator to be used
102 // for an MCDwarfLoc object.
105 /// Get the FileNum of this MCDwarfLoc.
106 unsigned getFileNum() const { return FileNum; }
108 /// Get the Line of this MCDwarfLoc.
109 unsigned getLine() const { return Line; }
111 /// Get the Column of this MCDwarfLoc.
112 unsigned getColumn() const { return Column; }
114 /// Get the Flags of this MCDwarfLoc.
115 unsigned getFlags() const { return Flags; }
117 /// Get the Isa of this MCDwarfLoc.
118 unsigned getIsa() const { return Isa; }
120 /// Get the Discriminator of this MCDwarfLoc.
121 unsigned getDiscriminator() const { return Discriminator; }
123 /// Set the FileNum of this MCDwarfLoc.
124 void setFileNum(unsigned fileNum) { FileNum = fileNum; }
126 /// Set the Line of this MCDwarfLoc.
127 void setLine(unsigned line) { Line = line; }
129 /// Set the Column of this MCDwarfLoc.
130 void setColumn(unsigned column) {
131 assert(column <= UINT16_MAX);
135 /// Set the Flags of this MCDwarfLoc.
136 void setFlags(unsigned flags) {
137 assert(flags <= UINT8_MAX);
141 /// Set the Isa of this MCDwarfLoc.
142 void setIsa(unsigned isa) {
143 assert(isa <= UINT8_MAX);
147 /// Set the Discriminator of this MCDwarfLoc.
148 void setDiscriminator(unsigned discriminator) {
149 Discriminator = discriminator;
153 /// Instances of this class represent the line information for
154 /// the dwarf line table entries. Which is created after a machine
155 /// instruction is assembled and uses an address from a temporary label
156 /// created at the current address in the current section and the info from
157 /// the last .loc directive seen as stored in the context.
158 class MCDwarfLineEntry : public MCDwarfLoc {
162 // Allow the default copy constructor and assignment operator to be used
163 // for an MCDwarfLineEntry object.
166 // Constructor to create an MCDwarfLineEntry given a symbol and the dwarf loc.
167 MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc)
168 : MCDwarfLoc(loc), Label(label) {}
170 MCSymbol *getLabel() const { return Label; }
172 // This is called when an instruction is assembled into the specified
173 // section and if there is information from the last .loc directive that
174 // has yet to have a line entry made for it is made.
175 static void Make(MCObjectStreamer *MCOS, MCSection *Section);
178 /// Instances of this class represent the line information for a compile
179 /// unit where machine instructions have been assembled after seeing .loc
180 /// directives. This is the information used to build the dwarf line
181 /// table for a section.
182 class MCLineSection {
184 // Add an entry to this MCLineSection's line entries.
185 void addLineEntry(const MCDwarfLineEntry &LineEntry, MCSection *Sec) {
186 MCLineDivisions[Sec].push_back(LineEntry);
189 using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>;
190 using iterator = MCDwarfLineEntryCollection::iterator;
191 using const_iterator = MCDwarfLineEntryCollection::const_iterator;
192 using MCLineDivisionMap = MapVector<MCSection *, MCDwarfLineEntryCollection>;
195 // A collection of MCDwarfLineEntry for each section.
196 MCLineDivisionMap MCLineDivisions;
199 // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID.
200 const MCLineDivisionMap &getMCLineEntries() const {
201 return MCLineDivisions;
205 struct MCDwarfLineTableParams {
206 /// First special line opcode - leave room for the standard opcodes.
207 /// Note: If you want to change this, you'll have to update the
208 /// "StandardOpcodeLengths" table that is emitted in
210 uint8_t DWARF2LineOpcodeBase = 13;
211 /// Minimum line offset in a special line info. opcode. The value
212 /// -5 was chosen to give a reasonable range of values.
213 int8_t DWARF2LineBase = -5;
214 /// Range of line offsets in a special line info. opcode.
215 uint8_t DWARF2LineRange = 14;
218 struct MCDwarfLineTableHeader {
219 MCSymbol *Label = nullptr;
220 SmallVector<std::string, 3> MCDwarfDirs;
221 SmallVector<MCDwarfFile, 3> MCDwarfFiles;
222 StringMap<unsigned> SourceIdMap;
223 std::string CompilationDir;
224 MCDwarfFile RootFile;
225 bool HasSource = false;
227 bool HasAllMD5 = true;
228 bool HasAnyMD5 = false;
231 MCDwarfLineTableHeader() = default;
233 Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
234 Optional<MD5::MD5Result> Checksum,
235 Optional<StringRef> Source,
236 uint16_t DwarfVersion,
237 unsigned FileNumber = 0);
238 std::pair<MCSymbol *, MCSymbol *>
239 Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
240 Optional<MCDwarfLineStr> &LineStr) const;
241 std::pair<MCSymbol *, MCSymbol *>
242 Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
243 ArrayRef<char> SpecialOpcodeLengths,
244 Optional<MCDwarfLineStr> &LineStr) const;
245 void resetMD5Usage() {
249 void trackMD5Usage(bool MD5Used) {
250 HasAllMD5 &= MD5Used;
251 HasAnyMD5 |= MD5Used;
253 bool isMD5UsageConsistent() const {
254 return MCDwarfFiles.empty() || (HasAllMD5 == HasAnyMD5);
257 void setRootFile(StringRef Directory, StringRef FileName,
258 Optional<MD5::MD5Result> Checksum,
259 Optional<StringRef> Source) {
260 CompilationDir = std::string(Directory);
261 RootFile.Name = std::string(FileName);
262 RootFile.DirIndex = 0;
263 RootFile.Checksum = Checksum;
264 RootFile.Source = Source;
265 trackMD5Usage(Checksum.hasValue());
266 HasSource = Source.hasValue();
269 void resetFileTable() {
271 MCDwarfFiles.clear();
272 RootFile.Name.clear();
278 void emitV2FileDirTables(MCStreamer *MCOS) const;
279 void emitV5FileDirTables(MCStreamer *MCOS, Optional<MCDwarfLineStr> &LineStr) const;
282 class MCDwarfDwoLineTable {
283 MCDwarfLineTableHeader Header;
284 bool HasSplitLineTable = false;
287 void maybeSetRootFile(StringRef Directory, StringRef FileName,
288 Optional<MD5::MD5Result> Checksum,
289 Optional<StringRef> Source) {
290 if (!Header.RootFile.Name.empty())
292 Header.setRootFile(Directory, FileName, Checksum, Source);
295 unsigned getFile(StringRef Directory, StringRef FileName,
296 Optional<MD5::MD5Result> Checksum, uint16_t DwarfVersion,
297 Optional<StringRef> Source) {
298 HasSplitLineTable = true;
299 return cantFail(Header.tryGetFile(Directory, FileName, Checksum, Source,
303 void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params,
304 MCSection *Section) const;
307 class MCDwarfLineTable {
308 MCDwarfLineTableHeader Header;
309 MCLineSection MCLineSections;
312 // This emits the Dwarf file and the line tables for all Compile Units.
313 static void Emit(MCObjectStreamer *MCOS, MCDwarfLineTableParams Params);
315 // This emits the Dwarf file and the line tables for a given Compile Unit.
316 void EmitCU(MCObjectStreamer *MCOS, MCDwarfLineTableParams Params,
317 Optional<MCDwarfLineStr> &LineStr) const;
319 Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
320 Optional<MD5::MD5Result> Checksum,
321 Optional<StringRef> Source,
322 uint16_t DwarfVersion,
323 unsigned FileNumber = 0);
324 unsigned getFile(StringRef &Directory, StringRef &FileName,
325 Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source,
326 uint16_t DwarfVersion, unsigned FileNumber = 0) {
327 return cantFail(tryGetFile(Directory, FileName, Checksum, Source,
328 DwarfVersion, FileNumber));
331 void setRootFile(StringRef Directory, StringRef FileName,
332 Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source) {
333 Header.CompilationDir = std::string(Directory);
334 Header.RootFile.Name = std::string(FileName);
335 Header.RootFile.DirIndex = 0;
336 Header.RootFile.Checksum = Checksum;
337 Header.RootFile.Source = Source;
338 Header.trackMD5Usage(Checksum.hasValue());
339 Header.HasSource = Source.hasValue();
342 void resetFileTable() { Header.resetFileTable(); }
344 bool hasRootFile() const { return !Header.RootFile.Name.empty(); }
346 const MCDwarfFile &getRootFile() const { return Header.RootFile; }
348 // Report whether MD5 usage has been consistent (all-or-none).
349 bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); }
351 MCSymbol *getLabel() const {
355 void setLabel(MCSymbol *Label) {
356 Header.Label = Label;
359 const SmallVectorImpl<std::string> &getMCDwarfDirs() const {
360 return Header.MCDwarfDirs;
363 SmallVectorImpl<std::string> &getMCDwarfDirs() {
364 return Header.MCDwarfDirs;
367 const SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() const {
368 return Header.MCDwarfFiles;
371 SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() {
372 return Header.MCDwarfFiles;
375 const MCLineSection &getMCLineSections() const {
376 return MCLineSections;
378 MCLineSection &getMCLineSections() {
379 return MCLineSections;
383 class MCDwarfLineAddr {
385 /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas.
386 static void Encode(MCContext &Context, MCDwarfLineTableParams Params,
387 int64_t LineDelta, uint64_t AddrDelta, raw_ostream &OS);
389 /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas using
390 /// fixed length operands.
391 static bool FixedEncode(MCContext &Context,
392 MCDwarfLineTableParams Params,
393 int64_t LineDelta, uint64_t AddrDelta,
394 raw_ostream &OS, uint32_t *Offset, uint32_t *Size);
396 /// Utility function to emit the encoding to a streamer.
397 static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
398 int64_t LineDelta, uint64_t AddrDelta);
401 class MCGenDwarfInfo {
404 // When generating dwarf for assembly source files this emits the Dwarf
407 static void Emit(MCStreamer *MCOS);
410 // When generating dwarf for assembly source files this is the info that is
411 // needed to be gathered for each symbol that will have a dwarf label.
412 class MCGenDwarfLabelEntry {
414 // Name of the symbol without a leading underbar, if any.
416 // The dwarf file number this symbol is in.
418 // The line number this symbol is at.
420 // The low_pc for the dwarf label is taken from this symbol.
424 MCGenDwarfLabelEntry(StringRef name, unsigned fileNumber, unsigned lineNumber,
426 : Name(name), FileNumber(fileNumber), LineNumber(lineNumber),
429 StringRef getName() const { return Name; }
430 unsigned getFileNumber() const { return FileNumber; }
431 unsigned getLineNumber() const { return LineNumber; }
432 MCSymbol *getLabel() const { return Label; }
434 // This is called when label is created when we are generating dwarf for
435 // assembly source files.
436 static void Make(MCSymbol *Symbol, MCStreamer *MCOS, SourceMgr &SrcMgr,
440 class MCCFIInstruction {
469 std::vector<char> Values;
472 MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, StringRef V,
473 StringRef Comment = "")
474 : Operation(Op), Label(L), Register(R), Offset(O),
475 Values(V.begin(), V.end()), Comment(Comment) {
476 assert(Op != OpRegister);
479 MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2)
480 : Operation(Op), Label(L), Register(R1), Register2(R2) {
481 assert(Op == OpRegister);
485 /// .cfi_def_cfa defines a rule for computing CFA as: take address from
486 /// Register and add Offset to it.
487 static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register,
489 return MCCFIInstruction(OpDefCfa, L, Register, Offset, "");
492 /// .cfi_def_cfa_register modifies a rule for computing CFA. From now
493 /// on Register will be used instead of the old one. Offset remains the same.
494 static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register) {
495 return MCCFIInstruction(OpDefCfaRegister, L, Register, 0, "");
498 /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register
499 /// remains the same, but offset is new. Note that it is the absolute offset
500 /// that will be added to a defined register to the compute CFA address.
501 static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int Offset) {
502 return MCCFIInstruction(OpDefCfaOffset, L, 0, Offset, "");
505 /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but
506 /// Offset is a relative value that is added/subtracted from the previous
508 static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int Adjustment) {
509 return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, "");
512 /// .cfi_offset Previous value of Register is saved at offset Offset
514 static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register,
516 return MCCFIInstruction(OpOffset, L, Register, Offset, "");
519 /// .cfi_rel_offset Previous value of Register is saved at offset
520 /// Offset from the current CFA register. This is transformed to .cfi_offset
521 /// using the known displacement of the CFA register from the CFA.
522 static MCCFIInstruction createRelOffset(MCSymbol *L, unsigned Register,
524 return MCCFIInstruction(OpRelOffset, L, Register, Offset, "");
527 /// .cfi_register Previous value of Register1 is saved in
528 /// register Register2.
529 static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1,
530 unsigned Register2) {
531 return MCCFIInstruction(OpRegister, L, Register1, Register2);
534 /// .cfi_window_save SPARC register window is saved.
535 static MCCFIInstruction createWindowSave(MCSymbol *L) {
536 return MCCFIInstruction(OpWindowSave, L, 0, 0, "");
539 /// .cfi_negate_ra_state AArch64 negate RA state.
540 static MCCFIInstruction createNegateRAState(MCSymbol *L) {
541 return MCCFIInstruction(OpNegateRAState, L, 0, 0, "");
544 /// .cfi_restore says that the rule for Register is now the same as it
545 /// was at the beginning of the function, after all initial instructions added
546 /// by .cfi_startproc were executed.
547 static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register) {
548 return MCCFIInstruction(OpRestore, L, Register, 0, "");
551 /// .cfi_undefined From now on the previous value of Register can't be
552 /// restored anymore.
553 static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register) {
554 return MCCFIInstruction(OpUndefined, L, Register, 0, "");
557 /// .cfi_same_value Current value of Register is the same as in the
558 /// previous frame. I.e., no restoration is needed.
559 static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register) {
560 return MCCFIInstruction(OpSameValue, L, Register, 0, "");
563 /// .cfi_remember_state Save all current rules for all registers.
564 static MCCFIInstruction createRememberState(MCSymbol *L) {
565 return MCCFIInstruction(OpRememberState, L, 0, 0, "");
568 /// .cfi_restore_state Restore the previously saved state.
569 static MCCFIInstruction createRestoreState(MCSymbol *L) {
570 return MCCFIInstruction(OpRestoreState, L, 0, 0, "");
573 /// .cfi_escape Allows the user to add arbitrary bytes to the unwind
575 static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals,
576 StringRef Comment = "") {
577 return MCCFIInstruction(OpEscape, L, 0, 0, Vals, Comment);
580 /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
581 static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int Size) {
582 return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, "");
585 OpType getOperation() const { return Operation; }
586 MCSymbol *getLabel() const { return Label; }
588 unsigned getRegister() const {
589 assert(Operation == OpDefCfa || Operation == OpOffset ||
590 Operation == OpRestore || Operation == OpUndefined ||
591 Operation == OpSameValue || Operation == OpDefCfaRegister ||
592 Operation == OpRelOffset || Operation == OpRegister);
596 unsigned getRegister2() const {
597 assert(Operation == OpRegister);
601 int getOffset() const {
602 assert(Operation == OpDefCfa || Operation == OpOffset ||
603 Operation == OpRelOffset || Operation == OpDefCfaOffset ||
604 Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize);
608 StringRef getValues() const {
609 assert(Operation == OpEscape);
610 return StringRef(&Values[0], Values.size());
613 StringRef getComment() const {
618 struct MCDwarfFrameInfo {
619 MCDwarfFrameInfo() = default;
621 MCSymbol *Begin = nullptr;
622 MCSymbol *End = nullptr;
623 const MCSymbol *Personality = nullptr;
624 const MCSymbol *Lsda = nullptr;
625 std::vector<MCCFIInstruction> Instructions;
626 unsigned CurrentCfaRegister = 0;
627 unsigned PersonalityEncoding = 0;
628 unsigned LsdaEncoding = 0;
629 uint32_t CompactUnwindEncoding = 0;
630 bool IsSignalFrame = false;
631 bool IsSimple = false;
632 unsigned RAReg = static_cast<unsigned>(INT_MAX);
633 bool IsBKeyFrame = false;
636 class MCDwarfFrameEmitter {
639 // This emits the frame info section.
641 static void Emit(MCObjectStreamer &streamer, MCAsmBackend *MAB, bool isEH);
642 static void EmitAdvanceLoc(MCObjectStreamer &Streamer, uint64_t AddrDelta);
643 static void EncodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta,
644 raw_ostream &OS, uint32_t *Offset = nullptr,
645 uint32_t *Size = nullptr);
648 } // end namespace llvm
650 #endif // LLVM_MC_MCDWARF_H