1//===- MCCodeView.h - Machine Code CodeView 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// Holds state from .cv_file and .cv_loc directives for later emission.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_MC_MCCODEVIEW_H
14#define LLVM_MC_MCCODEVIEW_H
15
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/DenseMap.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/ADT/StringMap.h"
20#include "llvm/ADT/StringRef.h"
21#include <map>
22#include <vector>
23
24namespace llvm {
25class MCAsmLayout;
26class MCCVDefRangeFragment;
27class MCCVInlineLineTableFragment;
28class MCDataFragment;
29class MCFragment;
30class MCSection;
31class MCSymbol;
32class MCContext;
33class MCObjectStreamer;
34class MCStreamer;
35
36/// Instances of this class represent the information from a
37/// .cv_loc directive.
38class MCCVLoc {
39  const MCSymbol *Label = nullptr;
40  uint32_t FunctionId;
41  uint32_t FileNum;
42  uint32_t Line;
43  uint16_t Column;
44  uint16_t PrologueEnd : 1;
45  uint16_t IsStmt : 1;
46
47private: // CodeViewContext manages these
48  friend class CodeViewContext;
49  MCCVLoc(const MCSymbol *Label, unsigned functionid, unsigned fileNum,
50          unsigned line, unsigned column, bool prologueend, bool isstmt)
51      : Label(Label), FunctionId(functionid), FileNum(fileNum), Line(line),
52        Column(column), PrologueEnd(prologueend), IsStmt(isstmt) {}
53
54  // Allow the default copy constructor and assignment operator to be used
55  // for an MCCVLoc object.
56
57public:
58  const MCSymbol *getLabel() const { return Label; }
59
60  unsigned getFunctionId() const { return FunctionId; }
61
62  /// Get the FileNum of this MCCVLoc.
63  unsigned getFileNum() const { return FileNum; }
64
65  /// Get the Line of this MCCVLoc.
66  unsigned getLine() const { return Line; }
67
68  /// Get the Column of this MCCVLoc.
69  unsigned getColumn() const { return Column; }
70
71  bool isPrologueEnd() const { return PrologueEnd; }
72  bool isStmt() const { return IsStmt; }
73
74  void setLabel(const MCSymbol *L) { Label = L; }
75
76  void setFunctionId(unsigned FID) { FunctionId = FID; }
77
78  /// Set the FileNum of this MCCVLoc.
79  void setFileNum(unsigned fileNum) { FileNum = fileNum; }
80
81  /// Set the Line of this MCCVLoc.
82  void setLine(unsigned line) { Line = line; }
83
84  /// Set the Column of this MCCVLoc.
85  void setColumn(unsigned column) {
86    assert(column <= UINT16_MAX);
87    Column = column;
88  }
89
90  void setPrologueEnd(bool PE) { PrologueEnd = PE; }
91  void setIsStmt(bool IS) { IsStmt = IS; }
92};
93
94/// Information describing a function or inlined call site introduced by
95/// .cv_func_id or .cv_inline_site_id. Accumulates information from .cv_loc
96/// directives used with this function's id or the id of an inlined call site
97/// within this function or inlined call site.
98struct MCCVFunctionInfo {
99  /// If this represents an inlined call site, then ParentFuncIdPlusOne will be
100  /// the parent function id plus one. If this represents a normal function,
101  /// then there is no parent, and ParentFuncIdPlusOne will be FunctionSentinel.
102  /// If this struct is an unallocated slot in the function info vector, then
103  /// ParentFuncIdPlusOne will be zero.
104  unsigned ParentFuncIdPlusOne = 0;
105
106  enum : unsigned { FunctionSentinel = ~0U };
107
108  struct LineInfo {
109    unsigned File;
110    unsigned Line;
111    unsigned Col;
112  };
113
114  LineInfo InlinedAt;
115
116  /// The section of the first .cv_loc directive used for this function, or null
117  /// if none has been seen yet.
118  MCSection *Section = nullptr;
119
120  /// Map from inlined call site id to the inlined at location to use for that
121  /// call site. Call chains are collapsed, so for the call chain 'f -> g -> h',
122  /// the InlinedAtMap of 'f' will contain entries for 'g' and 'h' that both
123  /// list the line info for the 'g' call site.
124  DenseMap<unsigned, LineInfo> InlinedAtMap;
125
126  /// Returns true if this is function info has not yet been used in a
127  /// .cv_func_id or .cv_inline_site_id directive.
128  bool isUnallocatedFunctionInfo() const { return ParentFuncIdPlusOne == 0; }
129
130  /// Returns true if this represents an inlined call site, meaning
131  /// ParentFuncIdPlusOne is neither zero nor ~0U.
132  bool isInlinedCallSite() const {
133    return !isUnallocatedFunctionInfo() &&
134           ParentFuncIdPlusOne != FunctionSentinel;
135  }
136
137  unsigned getParentFuncId() const {
138    assert(isInlinedCallSite());
139    return ParentFuncIdPlusOne - 1;
140  }
141};
142
143/// Holds state from .cv_file and .cv_loc directives for later emission.
144class CodeViewContext {
145public:
146  CodeViewContext();
147  ~CodeViewContext();
148
149  CodeViewContext &operator=(const CodeViewContext &other) = delete;
150  CodeViewContext(const CodeViewContext &other) = delete;
151
152  bool isValidFileNumber(unsigned FileNumber) const;
153  bool addFile(MCStreamer &OS, unsigned FileNumber, StringRef Filename,
154               ArrayRef<uint8_t> ChecksumBytes, uint8_t ChecksumKind);
155
156  /// Records the function id of a normal function. Returns false if the
157  /// function id has already been used, and true otherwise.
158  bool recordFunctionId(unsigned FuncId);
159
160  /// Records the function id of an inlined call site. Records the "inlined at"
161  /// location info of the call site, including what function or inlined call
162  /// site it was inlined into. Returns false if the function id has already
163  /// been used, and true otherwise.
164  bool recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
165                               unsigned IAFile, unsigned IALine,
166                               unsigned IACol);
167
168  /// Retreive the function info if this is a valid function id, or nullptr.
169  MCCVFunctionInfo *getCVFunctionInfo(unsigned FuncId);
170
171  /// Saves the information from the currently parsed .cv_loc directive
172  /// and sets CVLocSeen.  When the next instruction is assembled an entry
173  /// in the line number table with this information and the address of the
174  /// instruction will be created.
175  void recordCVLoc(MCContext &Ctx, const MCSymbol *Label, unsigned FunctionId,
176                   unsigned FileNo, unsigned Line, unsigned Column,
177                   bool PrologueEnd, bool IsStmt);
178
179  /// Add a line entry.
180  void addLineEntry(const MCCVLoc &LineEntry);
181
182  std::vector<MCCVLoc> getFunctionLineEntries(unsigned FuncId);
183
184  std::pair<size_t, size_t> getLineExtent(unsigned FuncId);
185  std::pair<size_t, size_t> getLineExtentIncludingInlinees(unsigned FuncId);
186
187  ArrayRef<MCCVLoc> getLinesForExtent(size_t L, size_t R);
188
189  /// Emits a line table substream.
190  void emitLineTableForFunction(MCObjectStreamer &OS, unsigned FuncId,
191                                const MCSymbol *FuncBegin,
192                                const MCSymbol *FuncEnd);
193
194  void emitInlineLineTableForFunction(MCObjectStreamer &OS,
195                                      unsigned PrimaryFunctionId,
196                                      unsigned SourceFileId,
197                                      unsigned SourceLineNum,
198                                      const MCSymbol *FnStartSym,
199                                      const MCSymbol *FnEndSym);
200
201  /// Encodes the binary annotations once we have a layout.
202  void encodeInlineLineTable(MCAsmLayout &Layout,
203                             MCCVInlineLineTableFragment &F);
204
205  MCFragment *
206  emitDefRange(MCObjectStreamer &OS,
207               ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
208               StringRef FixedSizePortion);
209
210  void encodeDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &F);
211
212  /// Emits the string table substream.
213  void emitStringTable(MCObjectStreamer &OS);
214
215  /// Emits the file checksum substream.
216  void emitFileChecksums(MCObjectStreamer &OS);
217
218  /// Emits the offset into the checksum table of the given file number.
219  void emitFileChecksumOffset(MCObjectStreamer &OS, unsigned FileNo);
220
221  /// Add something to the string table.  Returns the final string as well as
222  /// offset into the string table.
223  std::pair<StringRef, unsigned> addToStringTable(StringRef S);
224
225private:
226  /// Map from string to string table offset.
227  StringMap<unsigned> StringTable;
228
229  /// The fragment that ultimately holds our strings.
230  MCDataFragment *StrTabFragment = nullptr;
231  bool InsertedStrTabFragment = false;
232
233  MCDataFragment *getStringTableFragment();
234
235  /// Get a string table offset.
236  unsigned getStringTableOffset(StringRef S);
237
238  struct FileInfo {
239    unsigned StringTableOffset;
240
241    // Indicates if this FileInfo corresponds to an actual file, or hasn't been
242    // set yet.
243    bool Assigned = false;
244
245    uint8_t ChecksumKind;
246
247    ArrayRef<uint8_t> Checksum;
248
249    // Checksum offset stored as a symbol because it might be requested
250    // before it has been calculated, so a fixup may be needed.
251    MCSymbol *ChecksumTableOffset;
252  };
253
254  /// Array storing added file information.
255  SmallVector<FileInfo, 4> Files;
256
257  /// The offset of the first and last .cv_loc directive for a given function
258  /// id.
259  std::map<unsigned, std::pair<size_t, size_t>> MCCVLineStartStop;
260
261  /// A collection of MCCVLoc for each section.
262  std::vector<MCCVLoc> MCCVLines;
263
264  /// All known functions and inlined call sites, indexed by function id.
265  std::vector<MCCVFunctionInfo> Functions;
266
267  /// Indicate whether we have already laid out the checksum table addresses or
268  /// not.
269  bool ChecksumOffsetsAssigned = false;
270};
271
272} // end namespace llvm
273#endif
274