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