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 
24 namespace llvm {
25 class MCAsmLayout;
26 class MCCVDefRangeFragment;
27 class MCCVInlineLineTableFragment;
28 class MCDataFragment;
29 class MCFragment;
30 class MCSection;
31 class MCSymbol;
32 class MCContext;
33 class MCObjectStreamer;
34 class MCStreamer;
35 
36 /// Instances of this class represent the information from a
37 /// .cv_loc directive.
38 class 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 
47 private: // 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 
57 public:
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.
98 struct 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.
144 class CodeViewContext {
145 public:
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 
225 private:
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