blob: 70da5f76e76659597c94b46d2d466b8b9bdad66c [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- MCDwarf.h - Machine Code Dwarf support -------------------*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
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/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"
25#include <cassert>
26#include <cstdint>
27#include <string>
28#include <utility>
29#include <vector>
30
31namespace llvm {
32
33template <typename T> class ArrayRef;
34class MCAsmBackend;
35class MCContext;
36class MCDwarfLineStr;
37class MCObjectStreamer;
38class MCStreamer;
39class MCSymbol;
40class raw_ostream;
41class SMLoc;
42class SourceMgr;
43
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020044namespace mcdwarf {
45// Emit the common part of the DWARF 5 range/locations list tables header.
46MCSymbol *emitListsTableHeaderStart(MCStreamer &S);
47} // namespace mcdwarf
48
Andrew Walbran3d2c1972020-04-07 12:24:26 +010049/// 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
56/// vector.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010057struct MCDwarfFile {
Andrew Scullcdfcccc2018-10-05 20:58:37 +010058 // The base name of the file without its directory path.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010059 std::string Name;
60
Andrew Scullcdfcccc2018-10-05 20:58:37 +010061 // The index into the list of directory names for this file name.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020062 unsigned DirIndex = 0;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010063
64 /// The MD5 checksum, if there is one. Non-owning pointer to data allocated
65 /// in MCContext.
Andrew Walbran3d2c1972020-04-07 12:24:26 +010066 Optional<MD5::MD5Result> Checksum;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010067
68 /// The source code of the file. Non-owning reference to data allocated in
69 /// MCContext.
70 Optional<StringRef> Source;
71};
72
Andrew Scullcdfcccc2018-10-05 20:58:37 +010073/// Instances of this class represent the information from a
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010074/// dwarf .loc directive.
75class MCDwarfLoc {
76 uint32_t FileNum;
77 uint32_t Line;
78 uint16_t Column;
79 // Flags (see #define's below)
80 uint8_t Flags;
81 uint8_t Isa;
82 uint32_t Discriminator;
83
84// Flag that indicates the initial value of the is_stmt_start flag.
85#define DWARF2_LINE_DEFAULT_IS_STMT 1
86
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)
91
92private: // MCContext manages these
93 friend class MCContext;
94 friend class MCDwarfLineEntry;
95
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) {}
100
101 // Allow the default copy constructor and assignment operator to be used
102 // for an MCDwarfLoc object.
103
104public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100105 /// Get the FileNum of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100106 unsigned getFileNum() const { return FileNum; }
107
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100108 /// Get the Line of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100109 unsigned getLine() const { return Line; }
110
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100111 /// Get the Column of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100112 unsigned getColumn() const { return Column; }
113
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100114 /// Get the Flags of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100115 unsigned getFlags() const { return Flags; }
116
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100117 /// Get the Isa of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100118 unsigned getIsa() const { return Isa; }
119
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100120 /// Get the Discriminator of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100121 unsigned getDiscriminator() const { return Discriminator; }
122
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100123 /// Set the FileNum of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100124 void setFileNum(unsigned fileNum) { FileNum = fileNum; }
125
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100126 /// Set the Line of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100127 void setLine(unsigned line) { Line = line; }
128
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100129 /// Set the Column of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100130 void setColumn(unsigned column) {
131 assert(column <= UINT16_MAX);
132 Column = column;
133 }
134
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100135 /// Set the Flags of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100136 void setFlags(unsigned flags) {
137 assert(flags <= UINT8_MAX);
138 Flags = flags;
139 }
140
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100141 /// Set the Isa of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100142 void setIsa(unsigned isa) {
143 assert(isa <= UINT8_MAX);
144 Isa = isa;
145 }
146
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100147 /// Set the Discriminator of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100148 void setDiscriminator(unsigned discriminator) {
149 Discriminator = discriminator;
150 }
151};
152
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100153/// Instances of this class represent the line information for
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100154/// 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.
158class MCDwarfLineEntry : public MCDwarfLoc {
159 MCSymbol *Label;
160
161private:
162 // Allow the default copy constructor and assignment operator to be used
163 // for an MCDwarfLineEntry object.
164
165public:
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) {}
169
170 MCSymbol *getLabel() const { return Label; }
171
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);
176};
177
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100178/// Instances of this class represent the line information for a compile
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100179/// 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.
182class MCLineSection {
183public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100184 // Add an entry to this MCLineSection's line entries.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100185 void addLineEntry(const MCDwarfLineEntry &LineEntry, MCSection *Sec) {
186 MCLineDivisions[Sec].push_back(LineEntry);
187 }
188
189 using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>;
190 using iterator = MCDwarfLineEntryCollection::iterator;
191 using const_iterator = MCDwarfLineEntryCollection::const_iterator;
192 using MCLineDivisionMap = MapVector<MCSection *, MCDwarfLineEntryCollection>;
193
194private:
195 // A collection of MCDwarfLineEntry for each section.
196 MCLineDivisionMap MCLineDivisions;
197
198public:
199 // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID.
200 const MCLineDivisionMap &getMCLineEntries() const {
201 return MCLineDivisions;
202 }
203};
204
205struct 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
209 /// \c Emit().
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;
216};
217
218struct MCDwarfLineTableHeader {
219 MCSymbol *Label = nullptr;
220 SmallVector<std::string, 3> MCDwarfDirs;
221 SmallVector<MCDwarfFile, 3> MCDwarfFiles;
222 StringMap<unsigned> SourceIdMap;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100223 std::string CompilationDir;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100224 MCDwarfFile RootFile;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100225 bool HasSource = false;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100226private:
227 bool HasAllMD5 = true;
228 bool HasAnyMD5 = false;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100229
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100230public:
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100231 MCDwarfLineTableHeader() = default;
232
233 Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100234 Optional<MD5::MD5Result> Checksum,
235 Optional<StringRef> Source,
236 uint16_t DwarfVersion,
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100237 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;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100245 void resetMD5Usage() {
246 HasAllMD5 = true;
247 HasAnyMD5 = false;
248 }
249 void trackMD5Usage(bool MD5Used) {
250 HasAllMD5 &= MD5Used;
251 HasAnyMD5 |= MD5Used;
252 }
253 bool isMD5UsageConsistent() const {
254 return MCDwarfFiles.empty() || (HasAllMD5 == HasAnyMD5);
255 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100256
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100257 void setRootFile(StringRef Directory, StringRef FileName,
258 Optional<MD5::MD5Result> Checksum,
259 Optional<StringRef> Source) {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200260 CompilationDir = std::string(Directory);
261 RootFile.Name = std::string(FileName);
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100262 RootFile.DirIndex = 0;
263 RootFile.Checksum = Checksum;
264 RootFile.Source = Source;
265 trackMD5Usage(Checksum.hasValue());
266 HasSource = Source.hasValue();
267 }
268
269 void resetFileTable() {
270 MCDwarfDirs.clear();
271 MCDwarfFiles.clear();
272 RootFile.Name.clear();
273 resetMD5Usage();
274 HasSource = false;
275 }
276
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100277private:
278 void emitV2FileDirTables(MCStreamer *MCOS) const;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100279 void emitV5FileDirTables(MCStreamer *MCOS, Optional<MCDwarfLineStr> &LineStr) const;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100280};
281
282class MCDwarfDwoLineTable {
283 MCDwarfLineTableHeader Header;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100284 bool HasSplitLineTable = false;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100285
286public:
287 void maybeSetRootFile(StringRef Directory, StringRef FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100288 Optional<MD5::MD5Result> Checksum,
289 Optional<StringRef> Source) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100290 if (!Header.RootFile.Name.empty())
291 return;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100292 Header.setRootFile(Directory, FileName, Checksum, Source);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100293 }
294
295 unsigned getFile(StringRef Directory, StringRef FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100296 Optional<MD5::MD5Result> Checksum, uint16_t DwarfVersion,
297 Optional<StringRef> Source) {
298 HasSplitLineTable = true;
299 return cantFail(Header.tryGetFile(Directory, FileName, Checksum, Source,
300 DwarfVersion));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100301 }
302
303 void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params,
304 MCSection *Section) const;
305};
306
307class MCDwarfLineTable {
308 MCDwarfLineTableHeader Header;
309 MCLineSection MCLineSections;
310
311public:
312 // This emits the Dwarf file and the line tables for all Compile Units.
313 static void Emit(MCObjectStreamer *MCOS, MCDwarfLineTableParams Params);
314
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;
318
319 Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100320 Optional<MD5::MD5Result> Checksum,
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100321 Optional<StringRef> Source,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100322 uint16_t DwarfVersion,
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100323 unsigned FileNumber = 0);
324 unsigned getFile(StringRef &Directory, StringRef &FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100325 Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source,
326 uint16_t DwarfVersion, unsigned FileNumber = 0) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100327 return cantFail(tryGetFile(Directory, FileName, Checksum, Source,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100328 DwarfVersion, FileNumber));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100329 }
330
331 void setRootFile(StringRef Directory, StringRef FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100332 Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source) {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200333 Header.CompilationDir = std::string(Directory);
334 Header.RootFile.Name = std::string(FileName);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100335 Header.RootFile.DirIndex = 0;
336 Header.RootFile.Checksum = Checksum;
337 Header.RootFile.Source = Source;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100338 Header.trackMD5Usage(Checksum.hasValue());
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100339 Header.HasSource = Source.hasValue();
340 }
341
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100342 void resetFileTable() { Header.resetFileTable(); }
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100343
344 bool hasRootFile() const { return !Header.RootFile.Name.empty(); }
345
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100346 const MCDwarfFile &getRootFile() const { return Header.RootFile; }
347
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100348 // Report whether MD5 usage has been consistent (all-or-none).
349 bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); }
350
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100351 MCSymbol *getLabel() const {
352 return Header.Label;
353 }
354
355 void setLabel(MCSymbol *Label) {
356 Header.Label = Label;
357 }
358
359 const SmallVectorImpl<std::string> &getMCDwarfDirs() const {
360 return Header.MCDwarfDirs;
361 }
362
363 SmallVectorImpl<std::string> &getMCDwarfDirs() {
364 return Header.MCDwarfDirs;
365 }
366
367 const SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() const {
368 return Header.MCDwarfFiles;
369 }
370
371 SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() {
372 return Header.MCDwarfFiles;
373 }
374
375 const MCLineSection &getMCLineSections() const {
376 return MCLineSections;
377 }
378 MCLineSection &getMCLineSections() {
379 return MCLineSections;
380 }
381};
382
383class MCDwarfLineAddr {
384public:
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);
388
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100389 /// 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);
395
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100396 /// Utility function to emit the encoding to a streamer.
397 static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
398 int64_t LineDelta, uint64_t AddrDelta);
399};
400
401class MCGenDwarfInfo {
402public:
403 //
404 // When generating dwarf for assembly source files this emits the Dwarf
405 // sections.
406 //
407 static void Emit(MCStreamer *MCOS);
408};
409
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.
412class MCGenDwarfLabelEntry {
413private:
414 // Name of the symbol without a leading underbar, if any.
415 StringRef Name;
416 // The dwarf file number this symbol is in.
417 unsigned FileNumber;
418 // The line number this symbol is at.
419 unsigned LineNumber;
420 // The low_pc for the dwarf label is taken from this symbol.
421 MCSymbol *Label;
422
423public:
424 MCGenDwarfLabelEntry(StringRef name, unsigned fileNumber, unsigned lineNumber,
425 MCSymbol *label)
426 : Name(name), FileNumber(fileNumber), LineNumber(lineNumber),
427 Label(label) {}
428
429 StringRef getName() const { return Name; }
430 unsigned getFileNumber() const { return FileNumber; }
431 unsigned getLineNumber() const { return LineNumber; }
432 MCSymbol *getLabel() const { return Label; }
433
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,
437 SMLoc &Loc);
438};
439
440class MCCFIInstruction {
441public:
442 enum OpType {
443 OpSameValue,
444 OpRememberState,
445 OpRestoreState,
446 OpOffset,
447 OpDefCfaRegister,
448 OpDefCfaOffset,
449 OpDefCfa,
450 OpRelOffset,
451 OpAdjustCfaOffset,
452 OpEscape,
453 OpRestore,
454 OpUndefined,
455 OpRegister,
456 OpWindowSave,
Andrew Walbran16937d02019-10-22 13:54:20 +0100457 OpNegateRAState,
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100458 OpGnuArgsSize
459 };
460
461private:
462 OpType Operation;
463 MCSymbol *Label;
464 unsigned Register;
465 union {
466 int Offset;
467 unsigned Register2;
468 };
469 std::vector<char> Values;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200470 std::string Comment;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100471
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200472 MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int O, StringRef V,
473 StringRef Comment = "")
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100474 : Operation(Op), Label(L), Register(R), Offset(O),
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200475 Values(V.begin(), V.end()), Comment(Comment) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100476 assert(Op != OpRegister);
477 }
478
479 MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2)
480 : Operation(Op), Label(L), Register(R1), Register2(R2) {
481 assert(Op == OpRegister);
482 }
483
484public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100485 /// .cfi_def_cfa defines a rule for computing CFA as: take address from
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100486 /// Register and add Offset to it.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200487 static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register,
488 int Offset) {
489 return MCCFIInstruction(OpDefCfa, L, Register, Offset, "");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100490 }
491
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100492 /// .cfi_def_cfa_register modifies a rule for computing CFA. From now
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100493 /// 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, "");
496 }
497
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100498 /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100499 /// 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.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200501 static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int Offset) {
502 return MCCFIInstruction(OpDefCfaOffset, L, 0, Offset, "");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100503 }
504
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100505 /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100506 /// Offset is a relative value that is added/subtracted from the previous
507 /// offset.
508 static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int Adjustment) {
509 return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, "");
510 }
511
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100512 /// .cfi_offset Previous value of Register is saved at offset Offset
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100513 /// from CFA.
514 static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register,
515 int Offset) {
516 return MCCFIInstruction(OpOffset, L, Register, Offset, "");
517 }
518
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100519 /// .cfi_rel_offset Previous value of Register is saved at offset
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100520 /// 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,
523 int Offset) {
524 return MCCFIInstruction(OpRelOffset, L, Register, Offset, "");
525 }
526
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100527 /// .cfi_register Previous value of Register1 is saved in
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100528 /// register Register2.
529 static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1,
530 unsigned Register2) {
531 return MCCFIInstruction(OpRegister, L, Register1, Register2);
532 }
533
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100534 /// .cfi_window_save SPARC register window is saved.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100535 static MCCFIInstruction createWindowSave(MCSymbol *L) {
536 return MCCFIInstruction(OpWindowSave, L, 0, 0, "");
537 }
538
Andrew Walbran16937d02019-10-22 13:54:20 +0100539 /// .cfi_negate_ra_state AArch64 negate RA state.
540 static MCCFIInstruction createNegateRAState(MCSymbol *L) {
541 return MCCFIInstruction(OpNegateRAState, L, 0, 0, "");
542 }
543
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100544 /// .cfi_restore says that the rule for Register is now the same as it
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100545 /// 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, "");
549 }
550
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100551 /// .cfi_undefined From now on the previous value of Register can't be
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100552 /// restored anymore.
553 static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register) {
554 return MCCFIInstruction(OpUndefined, L, Register, 0, "");
555 }
556
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100557 /// .cfi_same_value Current value of Register is the same as in the
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100558 /// previous frame. I.e., no restoration is needed.
559 static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register) {
560 return MCCFIInstruction(OpSameValue, L, Register, 0, "");
561 }
562
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100563 /// .cfi_remember_state Save all current rules for all registers.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100564 static MCCFIInstruction createRememberState(MCSymbol *L) {
565 return MCCFIInstruction(OpRememberState, L, 0, 0, "");
566 }
567
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100568 /// .cfi_restore_state Restore the previously saved state.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100569 static MCCFIInstruction createRestoreState(MCSymbol *L) {
570 return MCCFIInstruction(OpRestoreState, L, 0, 0, "");
571 }
572
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100573 /// .cfi_escape Allows the user to add arbitrary bytes to the unwind
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100574 /// info.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200575 static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals,
576 StringRef Comment = "") {
577 return MCCFIInstruction(OpEscape, L, 0, 0, Vals, Comment);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100578 }
579
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100580 /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100581 static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int Size) {
582 return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, "");
583 }
584
585 OpType getOperation() const { return Operation; }
586 MCSymbol *getLabel() const { return Label; }
587
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);
593 return Register;
594 }
595
596 unsigned getRegister2() const {
597 assert(Operation == OpRegister);
598 return Register2;
599 }
600
601 int getOffset() const {
602 assert(Operation == OpDefCfa || Operation == OpOffset ||
603 Operation == OpRelOffset || Operation == OpDefCfaOffset ||
604 Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize);
605 return Offset;
606 }
607
608 StringRef getValues() const {
609 assert(Operation == OpEscape);
610 return StringRef(&Values[0], Values.size());
611 }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200612
613 StringRef getComment() const {
614 return Comment;
615 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100616};
617
618struct MCDwarfFrameInfo {
619 MCDwarfFrameInfo() = default;
620
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);
Andrew Walbran16937d02019-10-22 13:54:20 +0100633 bool IsBKeyFrame = false;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100634};
635
636class MCDwarfFrameEmitter {
637public:
638 //
639 // This emits the frame info section.
640 //
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,
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200644 raw_ostream &OS, uint32_t *Offset = nullptr,
645 uint32_t *Size = nullptr);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100646};
647
648} // end namespace llvm
649
650#endif // LLVM_MC_MCDWARF_H