1 | //===- MCDwarf.h - Machine Code Dwarf support -------------------*- C++ -*-===// |
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 the declaration of the MCDwarfFile to support the dwarf |
10 | // .file directive and the .loc directive. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_MC_MCDWARF_H |
15 | #define LLVM_MC_MCDWARF_H |
16 | |
17 | #include "llvm/ADT/MapVector.h" |
18 | #include "llvm/ADT/SmallVector.h" |
19 | #include "llvm/ADT/StringMap.h" |
20 | #include "llvm/ADT/StringRef.h" |
21 | #include "llvm/MC/StringTableBuilder.h" |
22 | #include "llvm/Support/Error.h" |
23 | #include "llvm/Support/MD5.h" |
24 | #include "llvm/Support/SMLoc.h" |
25 | #include "llvm/Support/StringSaver.h" |
26 | #include <cassert> |
27 | #include <cstdint> |
28 | #include <optional> |
29 | #include <string> |
30 | #include <utility> |
31 | #include <vector> |
32 | |
33 | namespace llvm { |
34 | |
35 | template <typename T> class ArrayRef; |
36 | class MCAsmBackend; |
37 | class MCContext; |
38 | class MCObjectStreamer; |
39 | class MCSection; |
40 | class MCStreamer; |
41 | class MCSymbol; |
42 | class raw_ostream; |
43 | class SourceMgr; |
44 | |
45 | namespace mcdwarf { |
46 | // Emit the common part of the DWARF 5 range/locations list tables header. |
47 | MCSymbol *(MCStreamer &S); |
48 | } // namespace mcdwarf |
49 | |
50 | /// Manage the .debug_line_str section contents, if we use it. |
51 | class MCDwarfLineStr { |
52 | BumpPtrAllocator Alloc; |
53 | StringSaver Saver{Alloc}; |
54 | MCSymbol *LineStrLabel = nullptr; |
55 | StringTableBuilder LineStrings{StringTableBuilder::DWARF}; |
56 | bool UseRelocs = false; |
57 | |
58 | public: |
59 | /// Construct an instance that can emit .debug_line_str (for use in a normal |
60 | /// v5 line table). |
61 | explicit MCDwarfLineStr(MCContext &Ctx); |
62 | |
63 | StringSaver &getSaver() { return Saver; } |
64 | |
65 | /// Emit a reference to the string. |
66 | void emitRef(MCStreamer *MCOS, StringRef Path); |
67 | |
68 | /// Emit the .debug_line_str section if appropriate. |
69 | void emitSection(MCStreamer *MCOS); |
70 | |
71 | /// Returns finalized section. |
72 | SmallString<0> getFinalizedData(); |
73 | |
74 | /// Adds path \p Path to the line string. Returns offset in the |
75 | /// .debug_line_str section. |
76 | size_t addString(StringRef Path); |
77 | }; |
78 | |
79 | /// Instances of this class represent the name of the dwarf .file directive and |
80 | /// its associated dwarf file number in the MC file. MCDwarfFile's are created |
81 | /// and uniqued by the MCContext class. In Dwarf 4 file numbers start from 1; |
82 | /// i.e. the entry with file number 1 is the first element in the vector of |
83 | /// DwarfFiles and there is no MCDwarfFile with file number 0. In Dwarf 5 file |
84 | /// numbers start from 0, with the MCDwarfFile with file number 0 being the |
85 | /// primary source file, and file numbers correspond to their index in the |
86 | /// vector. |
87 | struct MCDwarfFile { |
88 | // The base name of the file without its directory path. |
89 | std::string Name; |
90 | |
91 | // The index into the list of directory names for this file name. |
92 | unsigned DirIndex = 0; |
93 | |
94 | /// The MD5 checksum, if there is one. Non-owning pointer to data allocated |
95 | /// in MCContext. |
96 | std::optional<MD5::MD5Result> Checksum; |
97 | |
98 | /// The source code of the file. Non-owning reference to data allocated in |
99 | /// MCContext. |
100 | std::optional<StringRef> Source; |
101 | }; |
102 | |
103 | /// Instances of this class represent the information from a |
104 | /// dwarf .loc directive. |
105 | class MCDwarfLoc { |
106 | uint32_t FileNum; |
107 | uint32_t Line; |
108 | uint16_t Column; |
109 | // Flags (see #define's below) |
110 | uint8_t Flags; |
111 | uint8_t Isa; |
112 | uint32_t Discriminator; |
113 | |
114 | // Flag that indicates the initial value of the is_stmt_start flag. |
115 | #define DWARF2_LINE_DEFAULT_IS_STMT 1 |
116 | |
117 | #define DWARF2_FLAG_IS_STMT (1 << 0) |
118 | #define DWARF2_FLAG_BASIC_BLOCK (1 << 1) |
119 | #define DWARF2_FLAG_PROLOGUE_END (1 << 2) |
120 | #define DWARF2_FLAG_EPILOGUE_BEGIN (1 << 3) |
121 | |
122 | private: // MCContext manages these |
123 | friend class MCContext; |
124 | friend class MCDwarfLineEntry; |
125 | |
126 | MCDwarfLoc(unsigned fileNum, unsigned line, unsigned column, unsigned flags, |
127 | unsigned isa, unsigned discriminator) |
128 | : FileNum(fileNum), Line(line), Column(column), Flags(flags), Isa(isa), |
129 | Discriminator(discriminator) {} |
130 | |
131 | // Allow the default copy constructor and assignment operator to be used |
132 | // for an MCDwarfLoc object. |
133 | |
134 | public: |
135 | /// Get the FileNum of this MCDwarfLoc. |
136 | unsigned getFileNum() const { return FileNum; } |
137 | |
138 | /// Get the Line of this MCDwarfLoc. |
139 | unsigned getLine() const { return Line; } |
140 | |
141 | /// Get the Column of this MCDwarfLoc. |
142 | unsigned getColumn() const { return Column; } |
143 | |
144 | /// Get the Flags of this MCDwarfLoc. |
145 | unsigned getFlags() const { return Flags; } |
146 | |
147 | /// Get the Isa of this MCDwarfLoc. |
148 | unsigned getIsa() const { return Isa; } |
149 | |
150 | /// Get the Discriminator of this MCDwarfLoc. |
151 | unsigned getDiscriminator() const { return Discriminator; } |
152 | |
153 | /// Set the FileNum of this MCDwarfLoc. |
154 | void setFileNum(unsigned fileNum) { FileNum = fileNum; } |
155 | |
156 | /// Set the Line of this MCDwarfLoc. |
157 | void setLine(unsigned line) { Line = line; } |
158 | |
159 | /// Set the Column of this MCDwarfLoc. |
160 | void setColumn(unsigned column) { |
161 | assert(column <= UINT16_MAX); |
162 | Column = column; |
163 | } |
164 | |
165 | /// Set the Flags of this MCDwarfLoc. |
166 | void setFlags(unsigned flags) { |
167 | assert(flags <= UINT8_MAX); |
168 | Flags = flags; |
169 | } |
170 | |
171 | /// Set the Isa of this MCDwarfLoc. |
172 | void setIsa(unsigned isa) { |
173 | assert(isa <= UINT8_MAX); |
174 | Isa = isa; |
175 | } |
176 | |
177 | /// Set the Discriminator of this MCDwarfLoc. |
178 | void setDiscriminator(unsigned discriminator) { |
179 | Discriminator = discriminator; |
180 | } |
181 | }; |
182 | |
183 | /// Instances of this class represent the line information for |
184 | /// the dwarf line table entries. Which is created after a machine |
185 | /// instruction is assembled and uses an address from a temporary label |
186 | /// created at the current address in the current section and the info from |
187 | /// the last .loc directive seen as stored in the context. |
188 | class MCDwarfLineEntry : public MCDwarfLoc { |
189 | MCSymbol *Label; |
190 | |
191 | private: |
192 | // Allow the default copy constructor and assignment operator to be used |
193 | // for an MCDwarfLineEntry object. |
194 | |
195 | public: |
196 | // Constructor to create an MCDwarfLineEntry given a symbol and the dwarf loc. |
197 | MCDwarfLineEntry(MCSymbol *label, const MCDwarfLoc loc) |
198 | : MCDwarfLoc(loc), Label(label) {} |
199 | |
200 | MCSymbol *getLabel() const { return Label; } |
201 | |
202 | // This indicates the line entry is synthesized for an end entry. |
203 | bool IsEndEntry = false; |
204 | |
205 | // Override the label with the given EndLabel. |
206 | void setEndLabel(MCSymbol *EndLabel) { |
207 | Label = EndLabel; |
208 | IsEndEntry = true; |
209 | } |
210 | |
211 | // This is called when an instruction is assembled into the specified |
212 | // section and if there is information from the last .loc directive that |
213 | // has yet to have a line entry made for it is made. |
214 | static void make(MCStreamer *MCOS, MCSection *Section); |
215 | }; |
216 | |
217 | /// Instances of this class represent the line information for a compile |
218 | /// unit where machine instructions have been assembled after seeing .loc |
219 | /// directives. This is the information used to build the dwarf line |
220 | /// table for a section. |
221 | class MCLineSection { |
222 | public: |
223 | // Add an entry to this MCLineSection's line entries. |
224 | void addLineEntry(const MCDwarfLineEntry &LineEntry, MCSection *Sec) { |
225 | MCLineDivisions[Sec].push_back(x: LineEntry); |
226 | } |
227 | |
228 | // Add an end entry by cloning the last entry, if exists, for the section |
229 | // the given EndLabel belongs to. The label is replaced by the given EndLabel. |
230 | void addEndEntry(MCSymbol *EndLabel); |
231 | |
232 | using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>; |
233 | using iterator = MCDwarfLineEntryCollection::iterator; |
234 | using const_iterator = MCDwarfLineEntryCollection::const_iterator; |
235 | using MCLineDivisionMap = MapVector<MCSection *, MCDwarfLineEntryCollection>; |
236 | |
237 | private: |
238 | // A collection of MCDwarfLineEntry for each section. |
239 | MCLineDivisionMap MCLineDivisions; |
240 | |
241 | public: |
242 | // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID. |
243 | const MCLineDivisionMap &getMCLineEntries() const { |
244 | return MCLineDivisions; |
245 | } |
246 | }; |
247 | |
248 | struct MCDwarfLineTableParams { |
249 | /// First special line opcode - leave room for the standard opcodes. |
250 | /// Note: If you want to change this, you'll have to update the |
251 | /// "StandardOpcodeLengths" table that is emitted in |
252 | /// \c Emit(). |
253 | uint8_t DWARF2LineOpcodeBase = 13; |
254 | /// Minimum line offset in a special line info. opcode. The value |
255 | /// -5 was chosen to give a reasonable range of values. |
256 | int8_t DWARF2LineBase = -5; |
257 | /// Range of line offsets in a special line info. opcode. |
258 | uint8_t DWARF2LineRange = 14; |
259 | }; |
260 | |
261 | struct { |
262 | MCSymbol * = nullptr; |
263 | SmallVector<std::string, 3> ; |
264 | SmallVector<MCDwarfFile, 3> ; |
265 | StringMap<unsigned> ; |
266 | std::string ; |
267 | MCDwarfFile ; |
268 | bool = false; |
269 | |
270 | private: |
271 | bool = true; |
272 | bool = false; |
273 | |
274 | public: |
275 | () = default; |
276 | |
277 | Expected<unsigned> (StringRef &Directory, StringRef &FileName, |
278 | std::optional<MD5::MD5Result> Checksum, |
279 | std::optional<StringRef> Source, |
280 | uint16_t DwarfVersion, unsigned FileNumber = 0); |
281 | std::pair<MCSymbol *, MCSymbol *> |
282 | (MCStreamer *MCOS, MCDwarfLineTableParams Params, |
283 | std::optional<MCDwarfLineStr> &LineStr) const; |
284 | std::pair<MCSymbol *, MCSymbol *> |
285 | (MCStreamer *MCOS, MCDwarfLineTableParams Params, |
286 | ArrayRef<char> SpecialOpcodeLengths, |
287 | std::optional<MCDwarfLineStr> &LineStr) const; |
288 | void () { |
289 | HasAllMD5 = true; |
290 | HasAnyMD5 = false; |
291 | } |
292 | void (bool MD5Used) { |
293 | HasAllMD5 &= MD5Used; |
294 | HasAnyMD5 |= MD5Used; |
295 | } |
296 | bool () const { |
297 | return MCDwarfFiles.empty() || (HasAllMD5 == HasAnyMD5); |
298 | } |
299 | |
300 | void (StringRef Directory, StringRef FileName, |
301 | std::optional<MD5::MD5Result> Checksum, |
302 | std::optional<StringRef> Source) { |
303 | CompilationDir = std::string(Directory); |
304 | RootFile.Name = std::string(FileName); |
305 | RootFile.DirIndex = 0; |
306 | RootFile.Checksum = Checksum; |
307 | RootFile.Source = Source; |
308 | trackMD5Usage(MD5Used: Checksum.has_value()); |
309 | HasAnySource |= Source.has_value(); |
310 | } |
311 | |
312 | void () { |
313 | MCDwarfDirs.clear(); |
314 | MCDwarfFiles.clear(); |
315 | RootFile.Name.clear(); |
316 | resetMD5Usage(); |
317 | HasAnySource = false; |
318 | } |
319 | |
320 | private: |
321 | void (MCStreamer *MCOS) const; |
322 | void (MCStreamer *MCOS, |
323 | std::optional<MCDwarfLineStr> &LineStr) const; |
324 | }; |
325 | |
326 | class MCDwarfDwoLineTable { |
327 | MCDwarfLineTableHeader ; |
328 | bool HasSplitLineTable = false; |
329 | |
330 | public: |
331 | void maybeSetRootFile(StringRef Directory, StringRef FileName, |
332 | std::optional<MD5::MD5Result> Checksum, |
333 | std::optional<StringRef> Source) { |
334 | if (!Header.RootFile.Name.empty()) |
335 | return; |
336 | Header.setRootFile(Directory, FileName, Checksum, Source); |
337 | } |
338 | |
339 | unsigned getFile(StringRef Directory, StringRef FileName, |
340 | std::optional<MD5::MD5Result> Checksum, |
341 | uint16_t DwarfVersion, std::optional<StringRef> Source) { |
342 | HasSplitLineTable = true; |
343 | return cantFail(ValOrErr: Header.tryGetFile(Directory, FileName, Checksum, Source, |
344 | DwarfVersion)); |
345 | } |
346 | |
347 | void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params, |
348 | MCSection *Section) const; |
349 | }; |
350 | |
351 | class MCDwarfLineTable { |
352 | MCDwarfLineTableHeader ; |
353 | MCLineSection MCLineSections; |
354 | |
355 | public: |
356 | // This emits the Dwarf file and the line tables for all Compile Units. |
357 | static void emit(MCStreamer *MCOS, MCDwarfLineTableParams Params); |
358 | |
359 | // This emits the Dwarf file and the line tables for a given Compile Unit. |
360 | void emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params, |
361 | std::optional<MCDwarfLineStr> &LineStr) const; |
362 | |
363 | // This emits a single line table associated with a given Section. |
364 | static void |
365 | emitOne(MCStreamer *MCOS, MCSection *Section, |
366 | const MCLineSection::MCDwarfLineEntryCollection &LineEntries); |
367 | |
368 | Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName, |
369 | std::optional<MD5::MD5Result> Checksum, |
370 | std::optional<StringRef> Source, |
371 | uint16_t DwarfVersion, unsigned FileNumber = 0); |
372 | unsigned getFile(StringRef &Directory, StringRef &FileName, |
373 | std::optional<MD5::MD5Result> Checksum, |
374 | std::optional<StringRef> Source, uint16_t DwarfVersion, |
375 | unsigned FileNumber = 0) { |
376 | return cantFail(ValOrErr: tryGetFile(Directory, FileName, Checksum, Source, |
377 | DwarfVersion, FileNumber)); |
378 | } |
379 | |
380 | void setRootFile(StringRef Directory, StringRef FileName, |
381 | std::optional<MD5::MD5Result> Checksum, |
382 | std::optional<StringRef> Source) { |
383 | Header.CompilationDir = std::string(Directory); |
384 | Header.RootFile.Name = std::string(FileName); |
385 | Header.RootFile.DirIndex = 0; |
386 | Header.RootFile.Checksum = Checksum; |
387 | Header.RootFile.Source = Source; |
388 | Header.trackMD5Usage(MD5Used: Checksum.has_value()); |
389 | Header.HasAnySource |= Source.has_value(); |
390 | } |
391 | |
392 | void resetFileTable() { Header.resetFileTable(); } |
393 | |
394 | bool hasRootFile() const { return !Header.RootFile.Name.empty(); } |
395 | |
396 | MCDwarfFile &getRootFile() { return Header.RootFile; } |
397 | const MCDwarfFile &getRootFile() const { return Header.RootFile; } |
398 | |
399 | // Report whether MD5 usage has been consistent (all-or-none). |
400 | bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); } |
401 | |
402 | MCSymbol *getLabel() const { |
403 | return Header.Label; |
404 | } |
405 | |
406 | void setLabel(MCSymbol *Label) { |
407 | Header.Label = Label; |
408 | } |
409 | |
410 | const SmallVectorImpl<std::string> &getMCDwarfDirs() const { |
411 | return Header.MCDwarfDirs; |
412 | } |
413 | |
414 | SmallVectorImpl<std::string> &getMCDwarfDirs() { |
415 | return Header.MCDwarfDirs; |
416 | } |
417 | |
418 | const SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() const { |
419 | return Header.MCDwarfFiles; |
420 | } |
421 | |
422 | SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() { |
423 | return Header.MCDwarfFiles; |
424 | } |
425 | |
426 | const MCLineSection &getMCLineSections() const { |
427 | return MCLineSections; |
428 | } |
429 | MCLineSection &getMCLineSections() { |
430 | return MCLineSections; |
431 | } |
432 | }; |
433 | |
434 | class MCDwarfLineAddr { |
435 | public: |
436 | /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas. |
437 | static void encode(MCContext &Context, MCDwarfLineTableParams Params, |
438 | int64_t LineDelta, uint64_t AddrDelta, SmallVectorImpl<char> &OS); |
439 | |
440 | /// Utility function to emit the encoding to a streamer. |
441 | static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params, |
442 | int64_t LineDelta, uint64_t AddrDelta); |
443 | }; |
444 | |
445 | class MCGenDwarfInfo { |
446 | public: |
447 | // |
448 | // When generating dwarf for assembly source files this emits the Dwarf |
449 | // sections. |
450 | // |
451 | static void Emit(MCStreamer *MCOS); |
452 | }; |
453 | |
454 | // When generating dwarf for assembly source files this is the info that is |
455 | // needed to be gathered for each symbol that will have a dwarf label. |
456 | class MCGenDwarfLabelEntry { |
457 | private: |
458 | // Name of the symbol without a leading underbar, if any. |
459 | StringRef Name; |
460 | // The dwarf file number this symbol is in. |
461 | unsigned FileNumber; |
462 | // The line number this symbol is at. |
463 | unsigned LineNumber; |
464 | // The low_pc for the dwarf label is taken from this symbol. |
465 | MCSymbol *Label; |
466 | |
467 | public: |
468 | MCGenDwarfLabelEntry(StringRef name, unsigned fileNumber, unsigned lineNumber, |
469 | MCSymbol *label) |
470 | : Name(name), FileNumber(fileNumber), LineNumber(lineNumber), |
471 | Label(label) {} |
472 | |
473 | StringRef getName() const { return Name; } |
474 | unsigned getFileNumber() const { return FileNumber; } |
475 | unsigned getLineNumber() const { return LineNumber; } |
476 | MCSymbol *getLabel() const { return Label; } |
477 | |
478 | // This is called when label is created when we are generating dwarf for |
479 | // assembly source files. |
480 | static void Make(MCSymbol *Symbol, MCStreamer *MCOS, SourceMgr &SrcMgr, |
481 | SMLoc &Loc); |
482 | }; |
483 | |
484 | class MCCFIInstruction { |
485 | public: |
486 | enum OpType { |
487 | OpSameValue, |
488 | OpRememberState, |
489 | OpRestoreState, |
490 | OpOffset, |
491 | OpLLVMDefAspaceCfa, |
492 | OpDefCfaRegister, |
493 | OpDefCfaOffset, |
494 | OpDefCfa, |
495 | OpRelOffset, |
496 | OpAdjustCfaOffset, |
497 | OpEscape, |
498 | OpRestore, |
499 | OpUndefined, |
500 | OpRegister, |
501 | OpWindowSave, |
502 | OpNegateRAState, |
503 | OpGnuArgsSize |
504 | }; |
505 | |
506 | private: |
507 | OpType Operation; |
508 | MCSymbol *Label; |
509 | unsigned Register; |
510 | union { |
511 | int Offset; |
512 | unsigned Register2; |
513 | }; |
514 | unsigned AddressSpace = ~0u; |
515 | SMLoc Loc; |
516 | std::vector<char> Values; |
517 | std::string ; |
518 | |
519 | MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, SMLoc Loc, |
520 | StringRef V = "" , StringRef = "" ) |
521 | : Operation(Op), Label(L), Register(R), Offset(O), Loc(Loc), |
522 | Values(V.begin(), V.end()), Comment(Comment) { |
523 | assert(Op != OpRegister && Op != OpLLVMDefAspaceCfa); |
524 | } |
525 | |
526 | MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2, SMLoc Loc) |
527 | : Operation(Op), Label(L), Register(R1), Register2(R2), Loc(Loc) { |
528 | assert(Op == OpRegister); |
529 | } |
530 | |
531 | MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, unsigned AS, |
532 | SMLoc Loc) |
533 | : Operation(Op), Label(L), Register(R), Offset(O), AddressSpace(AS), |
534 | Loc(Loc) { |
535 | assert(Op == OpLLVMDefAspaceCfa); |
536 | } |
537 | |
538 | public: |
539 | /// .cfi_def_cfa defines a rule for computing CFA as: take address from |
540 | /// Register and add Offset to it. |
541 | static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register, int Offset, |
542 | SMLoc Loc = {}) { |
543 | return MCCFIInstruction(OpDefCfa, L, Register, Offset, Loc); |
544 | } |
545 | |
546 | /// .cfi_def_cfa_register modifies a rule for computing CFA. From now |
547 | /// on Register will be used instead of the old one. Offset remains the same. |
548 | static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register, |
549 | SMLoc Loc = {}) { |
550 | return MCCFIInstruction(OpDefCfaRegister, L, Register, 0, Loc); |
551 | } |
552 | |
553 | /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register |
554 | /// remains the same, but offset is new. Note that it is the absolute offset |
555 | /// that will be added to a defined register to the compute CFA address. |
556 | static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int Offset, |
557 | SMLoc Loc = {}) { |
558 | return MCCFIInstruction(OpDefCfaOffset, L, 0, Offset, Loc); |
559 | } |
560 | |
561 | /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but |
562 | /// Offset is a relative value that is added/subtracted from the previous |
563 | /// offset. |
564 | static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int Adjustment, |
565 | SMLoc Loc = {}) { |
566 | return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, Loc); |
567 | } |
568 | |
569 | // FIXME: Update the remaining docs to use the new proposal wording. |
570 | /// .cfi_llvm_def_aspace_cfa defines the rule for computing the CFA to |
571 | /// be the result of evaluating the DWARF operation expression |
572 | /// `DW_OP_constu AS; DW_OP_aspace_bregx R, B` as a location description. |
573 | static MCCFIInstruction createLLVMDefAspaceCfa(MCSymbol *L, unsigned Register, |
574 | int Offset, |
575 | unsigned AddressSpace, |
576 | SMLoc Loc) { |
577 | return MCCFIInstruction(OpLLVMDefAspaceCfa, L, Register, Offset, |
578 | AddressSpace, Loc); |
579 | } |
580 | |
581 | /// .cfi_offset Previous value of Register is saved at offset Offset |
582 | /// from CFA. |
583 | static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, |
584 | int Offset, SMLoc Loc = {}) { |
585 | return MCCFIInstruction(OpOffset, L, Register, Offset, Loc); |
586 | } |
587 | |
588 | /// .cfi_rel_offset Previous value of Register is saved at offset |
589 | /// Offset from the current CFA register. This is transformed to .cfi_offset |
590 | /// using the known displacement of the CFA register from the CFA. |
591 | static MCCFIInstruction createRelOffset(MCSymbol *L, unsigned Register, |
592 | int Offset, SMLoc Loc = {}) { |
593 | return MCCFIInstruction(OpRelOffset, L, Register, Offset, Loc); |
594 | } |
595 | |
596 | /// .cfi_register Previous value of Register1 is saved in |
597 | /// register Register2. |
598 | static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1, |
599 | unsigned Register2, SMLoc Loc = {}) { |
600 | return MCCFIInstruction(OpRegister, L, Register1, Register2, Loc); |
601 | } |
602 | |
603 | /// .cfi_window_save SPARC register window is saved. |
604 | static MCCFIInstruction createWindowSave(MCSymbol *L, SMLoc Loc = {}) { |
605 | return MCCFIInstruction(OpWindowSave, L, 0, 0, Loc); |
606 | } |
607 | |
608 | /// .cfi_negate_ra_state AArch64 negate RA state. |
609 | static MCCFIInstruction createNegateRAState(MCSymbol *L, SMLoc Loc = {}) { |
610 | return MCCFIInstruction(OpNegateRAState, L, 0, 0, Loc); |
611 | } |
612 | |
613 | /// .cfi_restore says that the rule for Register is now the same as it |
614 | /// was at the beginning of the function, after all initial instructions added |
615 | /// by .cfi_startproc were executed. |
616 | static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register, |
617 | SMLoc Loc = {}) { |
618 | return MCCFIInstruction(OpRestore, L, Register, 0, Loc); |
619 | } |
620 | |
621 | /// .cfi_undefined From now on the previous value of Register can't be |
622 | /// restored anymore. |
623 | static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register, |
624 | SMLoc Loc = {}) { |
625 | return MCCFIInstruction(OpUndefined, L, Register, 0, Loc); |
626 | } |
627 | |
628 | /// .cfi_same_value Current value of Register is the same as in the |
629 | /// previous frame. I.e., no restoration is needed. |
630 | static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register, |
631 | SMLoc Loc = {}) { |
632 | return MCCFIInstruction(OpSameValue, L, Register, 0, Loc); |
633 | } |
634 | |
635 | /// .cfi_remember_state Save all current rules for all registers. |
636 | static MCCFIInstruction createRememberState(MCSymbol *L, SMLoc Loc = {}) { |
637 | return MCCFIInstruction(OpRememberState, L, 0, 0, Loc); |
638 | } |
639 | |
640 | /// .cfi_restore_state Restore the previously saved state. |
641 | static MCCFIInstruction createRestoreState(MCSymbol *L, SMLoc Loc = {}) { |
642 | return MCCFIInstruction(OpRestoreState, L, 0, 0, Loc); |
643 | } |
644 | |
645 | /// .cfi_escape Allows the user to add arbitrary bytes to the unwind |
646 | /// info. |
647 | static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals, |
648 | SMLoc Loc = {}, StringRef = "" ) { |
649 | return MCCFIInstruction(OpEscape, L, 0, 0, Loc, Vals, Comment); |
650 | } |
651 | |
652 | /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE |
653 | static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int Size, |
654 | SMLoc Loc = {}) { |
655 | return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, Loc); |
656 | } |
657 | |
658 | OpType getOperation() const { return Operation; } |
659 | MCSymbol *getLabel() const { return Label; } |
660 | |
661 | unsigned getRegister() const { |
662 | assert(Operation == OpDefCfa || Operation == OpOffset || |
663 | Operation == OpRestore || Operation == OpUndefined || |
664 | Operation == OpSameValue || Operation == OpDefCfaRegister || |
665 | Operation == OpRelOffset || Operation == OpRegister || |
666 | Operation == OpLLVMDefAspaceCfa); |
667 | return Register; |
668 | } |
669 | |
670 | unsigned getRegister2() const { |
671 | assert(Operation == OpRegister); |
672 | return Register2; |
673 | } |
674 | |
675 | unsigned getAddressSpace() const { |
676 | assert(Operation == OpLLVMDefAspaceCfa); |
677 | return AddressSpace; |
678 | } |
679 | |
680 | int getOffset() const { |
681 | assert(Operation == OpDefCfa || Operation == OpOffset || |
682 | Operation == OpRelOffset || Operation == OpDefCfaOffset || |
683 | Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize || |
684 | Operation == OpLLVMDefAspaceCfa); |
685 | return Offset; |
686 | } |
687 | |
688 | StringRef getValues() const { |
689 | assert(Operation == OpEscape); |
690 | return StringRef(&Values[0], Values.size()); |
691 | } |
692 | |
693 | StringRef () const { return Comment; } |
694 | SMLoc getLoc() const { return Loc; } |
695 | }; |
696 | |
697 | struct MCDwarfFrameInfo { |
698 | MCDwarfFrameInfo() = default; |
699 | |
700 | MCSymbol *Begin = nullptr; |
701 | MCSymbol *End = nullptr; |
702 | const MCSymbol *Personality = nullptr; |
703 | const MCSymbol *Lsda = nullptr; |
704 | std::vector<MCCFIInstruction> Instructions; |
705 | unsigned CurrentCfaRegister = 0; |
706 | unsigned PersonalityEncoding = 0; |
707 | unsigned LsdaEncoding = 0; |
708 | uint32_t CompactUnwindEncoding = 0; |
709 | bool IsSignalFrame = false; |
710 | bool IsSimple = false; |
711 | unsigned RAReg = static_cast<unsigned>(INT_MAX); |
712 | bool IsBKeyFrame = false; |
713 | bool IsMTETaggedFrame = false; |
714 | }; |
715 | |
716 | class MCDwarfFrameEmitter { |
717 | public: |
718 | // |
719 | // This emits the frame info section. |
720 | // |
721 | static void Emit(MCObjectStreamer &streamer, MCAsmBackend *MAB, bool isEH); |
722 | static void encodeAdvanceLoc(MCContext &Context, uint64_t AddrDelta, |
723 | SmallVectorImpl<char> &OS); |
724 | }; |
725 | |
726 | } // end namespace llvm |
727 | |
728 | #endif // LLVM_MC_MCDWARF_H |
729 | |