1//===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Holds state from .cv_file and .cv_loc directives for later emission.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_MC_MCCODEVIEW_H
15#define LLVM_MC_MCCODEVIEW_H
16
17#include "llvm/ADT/StringMap.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/MC/MCFragment.h"
20#include "llvm/MC/MCObjectStreamer.h"
21#include <map>
22#include <vector>
23
24namespace llvm {
25class MCContext;
26class MCObjectStreamer;
27class MCStreamer;
28class CodeViewContext;
29
30/// \brief Instances of this class represent the information from a
31/// .cv_loc directive.
32class MCCVLoc {
33  uint32_t FunctionId;
34  uint32_t FileNum;
35  uint32_t Line;
36  uint16_t Column;
37  uint16_t PrologueEnd : 1;
38  uint16_t IsStmt : 1;
39
40private: // CodeViewContext manages these
41  friend class CodeViewContext;
42  MCCVLoc(unsigned functionid, unsigned fileNum, unsigned line, unsigned column,
43          bool prologueend, bool isstmt)
44      : FunctionId(functionid), FileNum(fileNum), Line(line), Column(column),
45        PrologueEnd(prologueend), IsStmt(isstmt) {}
46
47  // Allow the default copy constructor and assignment operator to be used
48  // for an MCCVLoc object.
49
50public:
51  unsigned getFunctionId() const { return FunctionId; }
52
53  /// \brief Get the FileNum of this MCCVLoc.
54  unsigned getFileNum() const { return FileNum; }
55
56  /// \brief Get the Line of this MCCVLoc.
57  unsigned getLine() const { return Line; }
58
59  /// \brief Get the Column of this MCCVLoc.
60  unsigned getColumn() const { return Column; }
61
62  bool isPrologueEnd() const { return PrologueEnd; }
63  bool isStmt() const { return IsStmt; }
64
65  void setFunctionId(unsigned FID) { FunctionId = FID; }
66
67  /// \brief Set the FileNum of this MCCVLoc.
68  void setFileNum(unsigned fileNum) { FileNum = fileNum; }
69
70  /// \brief Set the Line of this MCCVLoc.
71  void setLine(unsigned line) { Line = line; }
72
73  /// \brief Set the Column of this MCCVLoc.
74  void setColumn(unsigned column) {
75    assert(column <= UINT16_MAX);
76    Column = column;
77  }
78
79  void setPrologueEnd(bool PE) { PrologueEnd = PE; }
80  void setIsStmt(bool IS) { IsStmt = IS; }
81};
82
83/// \brief Instances of this class represent the line information for
84/// the CodeView line table entries.  Which is created after a machine
85/// instruction is assembled and uses an address from a temporary label
86/// created at the current address in the current section and the info from
87/// the last .cv_loc directive seen as stored in the context.
88class MCCVLineEntry : public MCCVLoc {
89  const MCSymbol *Label;
90
91private:
92  // Allow the default copy constructor and assignment operator to be used
93  // for an MCCVLineEntry object.
94
95public:
96  // Constructor to create an MCCVLineEntry given a symbol and the dwarf loc.
97  MCCVLineEntry(const MCSymbol *Label, const MCCVLoc loc)
98      : MCCVLoc(loc), Label(Label) {}
99
100  const MCSymbol *getLabel() const { return Label; }
101
102  // This is called when an instruction is assembled into the specified
103  // section and if there is information from the last .cv_loc directive that
104  // has yet to have a line entry made for it is made.
105  static void Make(MCObjectStreamer *MCOS);
106};
107
108/// Information describing a function or inlined call site introduced by
109/// .cv_func_id or .cv_inline_site_id. Accumulates information from .cv_loc
110/// directives used with this function's id or the id of an inlined call site
111/// within this function or inlined call site.
112struct MCCVFunctionInfo {
113  /// If this represents an inlined call site, then ParentFuncIdPlusOne will be
114  /// the parent function id plus one. If this represents a normal function,
115  /// then there is no parent, and ParentFuncIdPlusOne will be FunctionSentinel.
116  /// If this struct is an unallocated slot in the function info vector, then
117  /// ParentFuncIdPlusOne will be zero.
118  unsigned ParentFuncIdPlusOne = 0;
119
120  enum : unsigned { FunctionSentinel = ~0U };
121
122  struct LineInfo {
123    unsigned File;
124    unsigned Line;
125    unsigned Col;
126  };
127
128  LineInfo InlinedAt;
129
130  /// The section of the first .cv_loc directive used for this function, or null
131  /// if none has been seen yet.
132  MCSection *Section = nullptr;
133
134  /// Map from inlined call site id to the inlined at location to use for that
135  /// call site. Call chains are collapsed, so for the call chain 'f -> g -> h',
136  /// the InlinedAtMap of 'f' will contain entries for 'g' and 'h' that both
137  /// list the line info for the 'g' call site.
138  DenseMap<unsigned, LineInfo> InlinedAtMap;
139
140  /// Returns true if this is function info has not yet been used in a
141  /// .cv_func_id or .cv_inline_site_id directive.
142  bool isUnallocatedFunctionInfo() const { return ParentFuncIdPlusOne == 0; }
143
144  /// Returns true if this represents an inlined call site, meaning
145  /// ParentFuncIdPlusOne is neither zero nor ~0U.
146  bool isInlinedCallSite() const {
147    return !isUnallocatedFunctionInfo() &&
148           ParentFuncIdPlusOne != FunctionSentinel;
149  }
150
151  unsigned getParentFuncId() const {
152    assert(isInlinedCallSite());
153    return ParentFuncIdPlusOne - 1;
154  }
155};
156
157/// Holds state from .cv_file and .cv_loc directives for later emission.
158class CodeViewContext {
159public:
160  CodeViewContext();
161  ~CodeViewContext();
162
163  bool isValidFileNumber(unsigned FileNumber) const;
164  bool addFile(unsigned FileNumber, StringRef Filename);
165  ArrayRef<StringRef> getFilenames() { return Filenames; }
166
167  /// Records the function id of a normal function. Returns false if the
168  /// function id has already been used, and true otherwise.
169  bool recordFunctionId(unsigned FuncId);
170
171  /// Records the function id of an inlined call site. Records the "inlined at"
172  /// location info of the call site, including what function or inlined call
173  /// site it was inlined into. Returns false if the function id has already
174  /// been used, and true otherwise.
175  bool recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
176                               unsigned IAFile, unsigned IALine,
177                               unsigned IACol);
178
179  /// Retreive the function info if this is a valid function id, or nullptr.
180  MCCVFunctionInfo *getCVFunctionInfo(unsigned FuncId) {
181    if (FuncId >= Functions.size())
182      return nullptr;
183    if (Functions[FuncId].isUnallocatedFunctionInfo())
184      return nullptr;
185    return &Functions[FuncId];
186  }
187
188  /// Saves the information from the currently parsed .cv_loc directive
189  /// and sets CVLocSeen.  When the next instruction is assembled an entry
190  /// in the line number table with this information and the address of the
191  /// instruction will be created.
192  void setCurrentCVLoc(unsigned FunctionId, unsigned FileNo, unsigned Line,
193                       unsigned Column, bool PrologueEnd, bool IsStmt) {
194    CurrentCVLoc.setFunctionId(FunctionId);
195    CurrentCVLoc.setFileNum(FileNo);
196    CurrentCVLoc.setLine(Line);
197    CurrentCVLoc.setColumn(Column);
198    CurrentCVLoc.setPrologueEnd(PrologueEnd);
199    CurrentCVLoc.setIsStmt(IsStmt);
200    CVLocSeen = true;
201  }
202  void clearCVLocSeen() { CVLocSeen = false; }
203
204  bool getCVLocSeen() { return CVLocSeen; }
205  const MCCVLoc &getCurrentCVLoc() { return CurrentCVLoc; }
206
207  bool isValidCVFileNumber(unsigned FileNumber);
208
209  /// \brief Add a line entry.
210  void addLineEntry(const MCCVLineEntry &LineEntry) {
211    size_t Offset = MCCVLines.size();
212    auto I = MCCVLineStartStop.insert(
213        {LineEntry.getFunctionId(), {Offset, Offset + 1}});
214    if (!I.second)
215      I.first->second.second = Offset + 1;
216    MCCVLines.push_back(LineEntry);
217  }
218
219  std::vector<MCCVLineEntry> getFunctionLineEntries(unsigned FuncId) {
220    std::vector<MCCVLineEntry> FilteredLines;
221
222    auto I = MCCVLineStartStop.find(FuncId);
223    if (I != MCCVLineStartStop.end())
224      for (size_t Idx = I->second.first, End = I->second.second; Idx != End;
225           ++Idx)
226        if (MCCVLines[Idx].getFunctionId() == FuncId)
227          FilteredLines.push_back(MCCVLines[Idx]);
228    return FilteredLines;
229  }
230
231  std::pair<size_t, size_t> getLineExtent(unsigned FuncId) {
232    auto I = MCCVLineStartStop.find(FuncId);
233    // Return an empty extent if there are no cv_locs for this function id.
234    if (I == MCCVLineStartStop.end())
235      return {~0ULL, 0};
236    return I->second;
237  }
238
239  ArrayRef<MCCVLineEntry> getLinesForExtent(size_t L, size_t R) {
240    if (R <= L)
241      return None;
242    if (L >= MCCVLines.size())
243      return None;
244    return makeArrayRef(&MCCVLines[L], R - L);
245  }
246
247  /// Emits a line table substream.
248  void emitLineTableForFunction(MCObjectStreamer &OS, unsigned FuncId,
249                                const MCSymbol *FuncBegin,
250                                const MCSymbol *FuncEnd);
251
252  void emitInlineLineTableForFunction(MCObjectStreamer &OS,
253                                      unsigned PrimaryFunctionId,
254                                      unsigned SourceFileId,
255                                      unsigned SourceLineNum,
256                                      const MCSymbol *FnStartSym,
257                                      const MCSymbol *FnEndSym);
258
259  /// Encodes the binary annotations once we have a layout.
260  void encodeInlineLineTable(MCAsmLayout &Layout,
261                             MCCVInlineLineTableFragment &F);
262
263  void
264  emitDefRange(MCObjectStreamer &OS,
265               ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
266               StringRef FixedSizePortion);
267
268  void encodeDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &F);
269
270  /// Emits the string table substream.
271  void emitStringTable(MCObjectStreamer &OS);
272
273  /// Emits the file checksum substream.
274  void emitFileChecksums(MCObjectStreamer &OS);
275
276private:
277  /// The current CodeView line information from the last .cv_loc directive.
278  MCCVLoc CurrentCVLoc = MCCVLoc(0, 0, 0, 0, false, true);
279  bool CVLocSeen = false;
280
281  /// Map from string to string table offset.
282  StringMap<unsigned> StringTable;
283
284  /// The fragment that ultimately holds our strings.
285  MCDataFragment *StrTabFragment = nullptr;
286  bool InsertedStrTabFragment = false;
287
288  MCDataFragment *getStringTableFragment();
289
290  /// Add something to the string table.
291  StringRef addToStringTable(StringRef S);
292
293  /// Get a string table offset.
294  unsigned getStringTableOffset(StringRef S);
295
296  /// An array of absolute paths. Eventually this may include the file checksum.
297  SmallVector<StringRef, 4> Filenames;
298
299  /// The offset of the first and last .cv_loc directive for a given function
300  /// id.
301  std::map<unsigned, std::pair<size_t, size_t>> MCCVLineStartStop;
302
303  /// A collection of MCCVLineEntry for each section.
304  std::vector<MCCVLineEntry> MCCVLines;
305
306  /// All known functions and inlined call sites, indexed by function id.
307  std::vector<MCCVFunctionInfo> Functions;
308};
309
310} // end namespace llvm
311#endif
312