blob: 1a37aafd065422041537dee25dce4a03c750a884 [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
Andrew Walbran3d2c1972020-04-07 12:24:26 +010044/// 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
51/// vector.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010052struct MCDwarfFile {
Andrew Scullcdfcccc2018-10-05 20:58:37 +010053 // The base name of the file without its directory path.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010054 std::string Name;
55
Andrew Scullcdfcccc2018-10-05 20:58:37 +010056 // The index into the list of directory names for this file name.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010057 unsigned DirIndex;
58
59 /// The MD5 checksum, if there is one. Non-owning pointer to data allocated
60 /// in MCContext.
Andrew Walbran3d2c1972020-04-07 12:24:26 +010061 Optional<MD5::MD5Result> Checksum;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010062
63 /// The source code of the file. Non-owning reference to data allocated in
64 /// MCContext.
65 Optional<StringRef> Source;
66};
67
Andrew Scullcdfcccc2018-10-05 20:58:37 +010068/// Instances of this class represent the information from a
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010069/// dwarf .loc directive.
70class MCDwarfLoc {
71 uint32_t FileNum;
72 uint32_t Line;
73 uint16_t Column;
74 // Flags (see #define's below)
75 uint8_t Flags;
76 uint8_t Isa;
77 uint32_t Discriminator;
78
79// Flag that indicates the initial value of the is_stmt_start flag.
80#define DWARF2_LINE_DEFAULT_IS_STMT 1
81
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)
86
87private: // MCContext manages these
88 friend class MCContext;
89 friend class MCDwarfLineEntry;
90
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) {}
95
96 // Allow the default copy constructor and assignment operator to be used
97 // for an MCDwarfLoc object.
98
99public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100100 /// Get the FileNum of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100101 unsigned getFileNum() const { return FileNum; }
102
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100103 /// Get the Line of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100104 unsigned getLine() const { return Line; }
105
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100106 /// Get the Column of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100107 unsigned getColumn() const { return Column; }
108
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100109 /// Get the Flags of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100110 unsigned getFlags() const { return Flags; }
111
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100112 /// Get the Isa of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100113 unsigned getIsa() const { return Isa; }
114
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100115 /// Get the Discriminator of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100116 unsigned getDiscriminator() const { return Discriminator; }
117
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100118 /// Set the FileNum of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100119 void setFileNum(unsigned fileNum) { FileNum = fileNum; }
120
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100121 /// Set the Line of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100122 void setLine(unsigned line) { Line = line; }
123
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100124 /// Set the Column of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100125 void setColumn(unsigned column) {
126 assert(column <= UINT16_MAX);
127 Column = column;
128 }
129
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100130 /// Set the Flags of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100131 void setFlags(unsigned flags) {
132 assert(flags <= UINT8_MAX);
133 Flags = flags;
134 }
135
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100136 /// Set the Isa of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100137 void setIsa(unsigned isa) {
138 assert(isa <= UINT8_MAX);
139 Isa = isa;
140 }
141
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100142 /// Set the Discriminator of this MCDwarfLoc.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100143 void setDiscriminator(unsigned discriminator) {
144 Discriminator = discriminator;
145 }
146};
147
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100148/// Instances of this class represent the line information for
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100149/// 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.
153class MCDwarfLineEntry : public MCDwarfLoc {
154 MCSymbol *Label;
155
156private:
157 // Allow the default copy constructor and assignment operator to be used
158 // for an MCDwarfLineEntry object.
159
160public:
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) {}
164
165 MCSymbol *getLabel() const { return Label; }
166
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);
171};
172
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100173/// Instances of this class represent the line information for a compile
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100174/// 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.
177class MCLineSection {
178public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100179 // Add an entry to this MCLineSection's line entries.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100180 void addLineEntry(const MCDwarfLineEntry &LineEntry, MCSection *Sec) {
181 MCLineDivisions[Sec].push_back(LineEntry);
182 }
183
184 using MCDwarfLineEntryCollection = std::vector<MCDwarfLineEntry>;
185 using iterator = MCDwarfLineEntryCollection::iterator;
186 using const_iterator = MCDwarfLineEntryCollection::const_iterator;
187 using MCLineDivisionMap = MapVector<MCSection *, MCDwarfLineEntryCollection>;
188
189private:
190 // A collection of MCDwarfLineEntry for each section.
191 MCLineDivisionMap MCLineDivisions;
192
193public:
194 // Returns the collection of MCDwarfLineEntry for a given Compile Unit ID.
195 const MCLineDivisionMap &getMCLineEntries() const {
196 return MCLineDivisions;
197 }
198};
199
200struct 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
204 /// \c Emit().
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;
211};
212
213struct MCDwarfLineTableHeader {
214 MCSymbol *Label = nullptr;
215 SmallVector<std::string, 3> MCDwarfDirs;
216 SmallVector<MCDwarfFile, 3> MCDwarfFiles;
217 StringMap<unsigned> SourceIdMap;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100218 std::string CompilationDir;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100219 MCDwarfFile RootFile;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100220 bool HasSource = false;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100221private:
222 bool HasAllMD5 = true;
223 bool HasAnyMD5 = false;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100224
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100225public:
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100226 MCDwarfLineTableHeader() = default;
227
228 Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100229 Optional<MD5::MD5Result> Checksum,
230 Optional<StringRef> Source,
231 uint16_t DwarfVersion,
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100232 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;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100240 void resetMD5Usage() {
241 HasAllMD5 = true;
242 HasAnyMD5 = false;
243 }
244 void trackMD5Usage(bool MD5Used) {
245 HasAllMD5 &= MD5Used;
246 HasAnyMD5 |= MD5Used;
247 }
248 bool isMD5UsageConsistent() const {
249 return MCDwarfFiles.empty() || (HasAllMD5 == HasAnyMD5);
250 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100251
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100252 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();
262 }
263
264 void resetFileTable() {
265 MCDwarfDirs.clear();
266 MCDwarfFiles.clear();
267 RootFile.Name.clear();
268 resetMD5Usage();
269 HasSource = false;
270 }
271
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100272private:
273 void emitV2FileDirTables(MCStreamer *MCOS) const;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100274 void emitV5FileDirTables(MCStreamer *MCOS, Optional<MCDwarfLineStr> &LineStr) const;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100275};
276
277class MCDwarfDwoLineTable {
278 MCDwarfLineTableHeader Header;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100279 bool HasSplitLineTable = false;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100280
281public:
282 void maybeSetRootFile(StringRef Directory, StringRef FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100283 Optional<MD5::MD5Result> Checksum,
284 Optional<StringRef> Source) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100285 if (!Header.RootFile.Name.empty())
286 return;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100287 Header.setRootFile(Directory, FileName, Checksum, Source);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100288 }
289
290 unsigned getFile(StringRef Directory, StringRef FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100291 Optional<MD5::MD5Result> Checksum, uint16_t DwarfVersion,
292 Optional<StringRef> Source) {
293 HasSplitLineTable = true;
294 return cantFail(Header.tryGetFile(Directory, FileName, Checksum, Source,
295 DwarfVersion));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100296 }
297
298 void Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params,
299 MCSection *Section) const;
300};
301
302class MCDwarfLineTable {
303 MCDwarfLineTableHeader Header;
304 MCLineSection MCLineSections;
305
306public:
307 // This emits the Dwarf file and the line tables for all Compile Units.
308 static void Emit(MCObjectStreamer *MCOS, MCDwarfLineTableParams Params);
309
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;
313
314 Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100315 Optional<MD5::MD5Result> Checksum,
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100316 Optional<StringRef> Source,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100317 uint16_t DwarfVersion,
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100318 unsigned FileNumber = 0);
319 unsigned getFile(StringRef &Directory, StringRef &FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100320 Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source,
321 uint16_t DwarfVersion, unsigned FileNumber = 0) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100322 return cantFail(tryGetFile(Directory, FileName, Checksum, Source,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100323 DwarfVersion, FileNumber));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100324 }
325
326 void setRootFile(StringRef Directory, StringRef FileName,
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100327 Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100328 Header.CompilationDir = Directory;
329 Header.RootFile.Name = FileName;
330 Header.RootFile.DirIndex = 0;
331 Header.RootFile.Checksum = Checksum;
332 Header.RootFile.Source = Source;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100333 Header.trackMD5Usage(Checksum.hasValue());
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100334 Header.HasSource = Source.hasValue();
335 }
336
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100337 void resetFileTable() { Header.resetFileTable(); }
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100338
339 bool hasRootFile() const { return !Header.RootFile.Name.empty(); }
340
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100341 const MCDwarfFile &getRootFile() const { return Header.RootFile; }
342
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100343 // Report whether MD5 usage has been consistent (all-or-none).
344 bool isMD5UsageConsistent() const { return Header.isMD5UsageConsistent(); }
345
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100346 MCSymbol *getLabel() const {
347 return Header.Label;
348 }
349
350 void setLabel(MCSymbol *Label) {
351 Header.Label = Label;
352 }
353
354 const SmallVectorImpl<std::string> &getMCDwarfDirs() const {
355 return Header.MCDwarfDirs;
356 }
357
358 SmallVectorImpl<std::string> &getMCDwarfDirs() {
359 return Header.MCDwarfDirs;
360 }
361
362 const SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() const {
363 return Header.MCDwarfFiles;
364 }
365
366 SmallVectorImpl<MCDwarfFile> &getMCDwarfFiles() {
367 return Header.MCDwarfFiles;
368 }
369
370 const MCLineSection &getMCLineSections() const {
371 return MCLineSections;
372 }
373 MCLineSection &getMCLineSections() {
374 return MCLineSections;
375 }
376};
377
378class MCDwarfLineAddr {
379public:
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);
383
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100384 /// 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);
390
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100391 /// Utility function to emit the encoding to a streamer.
392 static void Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
393 int64_t LineDelta, uint64_t AddrDelta);
394};
395
396class MCGenDwarfInfo {
397public:
398 //
399 // When generating dwarf for assembly source files this emits the Dwarf
400 // sections.
401 //
402 static void Emit(MCStreamer *MCOS);
403};
404
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.
407class MCGenDwarfLabelEntry {
408private:
409 // Name of the symbol without a leading underbar, if any.
410 StringRef Name;
411 // The dwarf file number this symbol is in.
412 unsigned FileNumber;
413 // The line number this symbol is at.
414 unsigned LineNumber;
415 // The low_pc for the dwarf label is taken from this symbol.
416 MCSymbol *Label;
417
418public:
419 MCGenDwarfLabelEntry(StringRef name, unsigned fileNumber, unsigned lineNumber,
420 MCSymbol *label)
421 : Name(name), FileNumber(fileNumber), LineNumber(lineNumber),
422 Label(label) {}
423
424 StringRef getName() const { return Name; }
425 unsigned getFileNumber() const { return FileNumber; }
426 unsigned getLineNumber() const { return LineNumber; }
427 MCSymbol *getLabel() const { return Label; }
428
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,
432 SMLoc &Loc);
433};
434
435class MCCFIInstruction {
436public:
437 enum OpType {
438 OpSameValue,
439 OpRememberState,
440 OpRestoreState,
441 OpOffset,
442 OpDefCfaRegister,
443 OpDefCfaOffset,
444 OpDefCfa,
445 OpRelOffset,
446 OpAdjustCfaOffset,
447 OpEscape,
448 OpRestore,
449 OpUndefined,
450 OpRegister,
451 OpWindowSave,
Andrew Walbran16937d02019-10-22 13:54:20 +0100452 OpNegateRAState,
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100453 OpGnuArgsSize
454 };
455
456private:
457 OpType Operation;
458 MCSymbol *Label;
459 unsigned Register;
460 union {
461 int Offset;
462 unsigned Register2;
463 };
464 std::vector<char> Values;
465
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);
470 }
471
472 MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2)
473 : Operation(Op), Label(L), Register(R1), Register2(R2) {
474 assert(Op == OpRegister);
475 }
476
477public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100478 /// .cfi_def_cfa defines a rule for computing CFA as: take address from
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100479 /// Register and add Offset to it.
480 static MCCFIInstruction createDefCfa(MCSymbol *L, unsigned Register,
481 int Offset) {
482 return MCCFIInstruction(OpDefCfa, L, Register, -Offset, "");
483 }
484
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100485 /// .cfi_def_cfa_register modifies a rule for computing CFA. From now
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100486 /// 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, "");
489 }
490
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100491 /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100492 /// 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, "");
496 }
497
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100498 /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100499 /// Offset is a relative value that is added/subtracted from the previous
500 /// offset.
501 static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int Adjustment) {
502 return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, "");
503 }
504
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100505 /// .cfi_offset Previous value of Register is saved at offset Offset
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100506 /// from CFA.
507 static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register,
508 int Offset) {
509 return MCCFIInstruction(OpOffset, L, Register, Offset, "");
510 }
511
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100512 /// .cfi_rel_offset Previous value of Register is saved at offset
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100513 /// 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,
516 int Offset) {
517 return MCCFIInstruction(OpRelOffset, L, Register, Offset, "");
518 }
519
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100520 /// .cfi_register Previous value of Register1 is saved in
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100521 /// register Register2.
522 static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1,
523 unsigned Register2) {
524 return MCCFIInstruction(OpRegister, L, Register1, Register2);
525 }
526
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100527 /// .cfi_window_save SPARC register window is saved.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100528 static MCCFIInstruction createWindowSave(MCSymbol *L) {
529 return MCCFIInstruction(OpWindowSave, L, 0, 0, "");
530 }
531
Andrew Walbran16937d02019-10-22 13:54:20 +0100532 /// .cfi_negate_ra_state AArch64 negate RA state.
533 static MCCFIInstruction createNegateRAState(MCSymbol *L) {
534 return MCCFIInstruction(OpNegateRAState, L, 0, 0, "");
535 }
536
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100537 /// .cfi_restore says that the rule for Register is now the same as it
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100538 /// 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, "");
542 }
543
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100544 /// .cfi_undefined From now on the previous value of Register can't be
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100545 /// restored anymore.
546 static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register) {
547 return MCCFIInstruction(OpUndefined, L, Register, 0, "");
548 }
549
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100550 /// .cfi_same_value Current value of Register is the same as in the
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100551 /// previous frame. I.e., no restoration is needed.
552 static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register) {
553 return MCCFIInstruction(OpSameValue, L, Register, 0, "");
554 }
555
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100556 /// .cfi_remember_state Save all current rules for all registers.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100557 static MCCFIInstruction createRememberState(MCSymbol *L) {
558 return MCCFIInstruction(OpRememberState, L, 0, 0, "");
559 }
560
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100561 /// .cfi_restore_state Restore the previously saved state.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100562 static MCCFIInstruction createRestoreState(MCSymbol *L) {
563 return MCCFIInstruction(OpRestoreState, L, 0, 0, "");
564 }
565
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100566 /// .cfi_escape Allows the user to add arbitrary bytes to the unwind
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100567 /// info.
568 static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals) {
569 return MCCFIInstruction(OpEscape, L, 0, 0, Vals);
570 }
571
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100572 /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100573 static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int Size) {
574 return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, "");
575 }
576
577 OpType getOperation() const { return Operation; }
578 MCSymbol *getLabel() const { return Label; }
579
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);
585 return Register;
586 }
587
588 unsigned getRegister2() const {
589 assert(Operation == OpRegister);
590 return Register2;
591 }
592
593 int getOffset() const {
594 assert(Operation == OpDefCfa || Operation == OpOffset ||
595 Operation == OpRelOffset || Operation == OpDefCfaOffset ||
596 Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize);
597 return Offset;
598 }
599
600 StringRef getValues() const {
601 assert(Operation == OpEscape);
602 return StringRef(&Values[0], Values.size());
603 }
604};
605
606struct MCDwarfFrameInfo {
607 MCDwarfFrameInfo() = default;
608
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);
Andrew Walbran16937d02019-10-22 13:54:20 +0100621 bool IsBKeyFrame = false;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100622};
623
624class MCDwarfFrameEmitter {
625public:
626 //
627 // This emits the frame info section.
628 //
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);
633};
634
635} // end namespace llvm
636
637#endif // LLVM_MC_MCDWARF_H