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