10b57cec5SDimitry Andric //===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // Holds state from .cv_file and .cv_loc directives for later emission. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #ifndef LLVM_MC_MCCODEVIEW_H 140b57cec5SDimitry Andric #define LLVM_MC_MCCODEVIEW_H 150b57cec5SDimitry Andric 1681ad6265SDimitry Andric #include "llvm/ADT/ArrayRef.h" 1781ad6265SDimitry Andric #include "llvm/ADT/DenseMap.h" 1881ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h" 190b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h" 200b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 210b57cec5SDimitry Andric #include <map> 220b57cec5SDimitry Andric #include <vector> 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace llvm { 25*0fca6ea1SDimitry Andric class MCAssembler; 2681ad6265SDimitry Andric class MCCVDefRangeFragment; 2781ad6265SDimitry Andric class MCCVInlineLineTableFragment; 2881ad6265SDimitry Andric class MCDataFragment; 2981ad6265SDimitry Andric class MCFragment; 3081ad6265SDimitry Andric class MCSection; 3181ad6265SDimitry Andric class MCSymbol; 320b57cec5SDimitry Andric class MCContext; 330b57cec5SDimitry Andric class MCObjectStreamer; 340b57cec5SDimitry Andric class MCStreamer; 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric /// Instances of this class represent the information from a 370b57cec5SDimitry Andric /// .cv_loc directive. 380b57cec5SDimitry Andric class MCCVLoc { 390b57cec5SDimitry Andric const MCSymbol *Label = nullptr; 400b57cec5SDimitry Andric uint32_t FunctionId; 410b57cec5SDimitry Andric uint32_t FileNum; 420b57cec5SDimitry Andric uint32_t Line; 430b57cec5SDimitry Andric uint16_t Column; 440b57cec5SDimitry Andric uint16_t PrologueEnd : 1; 450b57cec5SDimitry Andric uint16_t IsStmt : 1; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric private: // CodeViewContext manages these 480b57cec5SDimitry Andric friend class CodeViewContext; 490b57cec5SDimitry Andric MCCVLoc(const MCSymbol *Label, unsigned functionid, unsigned fileNum, 500b57cec5SDimitry Andric unsigned line, unsigned column, bool prologueend, bool isstmt) 510b57cec5SDimitry Andric : Label(Label), FunctionId(functionid), FileNum(fileNum), Line(line), 520b57cec5SDimitry Andric Column(column), PrologueEnd(prologueend), IsStmt(isstmt) {} 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric // Allow the default copy constructor and assignment operator to be used 550b57cec5SDimitry Andric // for an MCCVLoc object. 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric public: 580b57cec5SDimitry Andric const MCSymbol *getLabel() const { return Label; } 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric unsigned getFunctionId() const { return FunctionId; } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric /// Get the FileNum of this MCCVLoc. 630b57cec5SDimitry Andric unsigned getFileNum() const { return FileNum; } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric /// Get the Line of this MCCVLoc. 660b57cec5SDimitry Andric unsigned getLine() const { return Line; } 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric /// Get the Column of this MCCVLoc. 690b57cec5SDimitry Andric unsigned getColumn() const { return Column; } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric bool isPrologueEnd() const { return PrologueEnd; } 720b57cec5SDimitry Andric bool isStmt() const { return IsStmt; } 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric void setLabel(const MCSymbol *L) { Label = L; } 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric void setFunctionId(unsigned FID) { FunctionId = FID; } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric /// Set the FileNum of this MCCVLoc. 790b57cec5SDimitry Andric void setFileNum(unsigned fileNum) { FileNum = fileNum; } 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric /// Set the Line of this MCCVLoc. 820b57cec5SDimitry Andric void setLine(unsigned line) { Line = line; } 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric /// Set the Column of this MCCVLoc. 850b57cec5SDimitry Andric void setColumn(unsigned column) { 860b57cec5SDimitry Andric assert(column <= UINT16_MAX); 870b57cec5SDimitry Andric Column = column; 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric void setPrologueEnd(bool PE) { PrologueEnd = PE; } 910b57cec5SDimitry Andric void setIsStmt(bool IS) { IsStmt = IS; } 920b57cec5SDimitry Andric }; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric /// Information describing a function or inlined call site introduced by 950b57cec5SDimitry Andric /// .cv_func_id or .cv_inline_site_id. Accumulates information from .cv_loc 960b57cec5SDimitry Andric /// directives used with this function's id or the id of an inlined call site 970b57cec5SDimitry Andric /// within this function or inlined call site. 980b57cec5SDimitry Andric struct MCCVFunctionInfo { 990b57cec5SDimitry Andric /// If this represents an inlined call site, then ParentFuncIdPlusOne will be 1000b57cec5SDimitry Andric /// the parent function id plus one. If this represents a normal function, 1010b57cec5SDimitry Andric /// then there is no parent, and ParentFuncIdPlusOne will be FunctionSentinel. 1020b57cec5SDimitry Andric /// If this struct is an unallocated slot in the function info vector, then 1030b57cec5SDimitry Andric /// ParentFuncIdPlusOne will be zero. 1040b57cec5SDimitry Andric unsigned ParentFuncIdPlusOne = 0; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric enum : unsigned { FunctionSentinel = ~0U }; 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric struct LineInfo { 1090b57cec5SDimitry Andric unsigned File; 1100b57cec5SDimitry Andric unsigned Line; 1110b57cec5SDimitry Andric unsigned Col; 1120b57cec5SDimitry Andric }; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric LineInfo InlinedAt; 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric /// The section of the first .cv_loc directive used for this function, or null 1170b57cec5SDimitry Andric /// if none has been seen yet. 1180b57cec5SDimitry Andric MCSection *Section = nullptr; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric /// Map from inlined call site id to the inlined at location to use for that 1210b57cec5SDimitry Andric /// call site. Call chains are collapsed, so for the call chain 'f -> g -> h', 1220b57cec5SDimitry Andric /// the InlinedAtMap of 'f' will contain entries for 'g' and 'h' that both 1230b57cec5SDimitry Andric /// list the line info for the 'g' call site. 1240b57cec5SDimitry Andric DenseMap<unsigned, LineInfo> InlinedAtMap; 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric /// Returns true if this is function info has not yet been used in a 1270b57cec5SDimitry Andric /// .cv_func_id or .cv_inline_site_id directive. 1280b57cec5SDimitry Andric bool isUnallocatedFunctionInfo() const { return ParentFuncIdPlusOne == 0; } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric /// Returns true if this represents an inlined call site, meaning 1310b57cec5SDimitry Andric /// ParentFuncIdPlusOne is neither zero nor ~0U. 1320b57cec5SDimitry Andric bool isInlinedCallSite() const { 1330b57cec5SDimitry Andric return !isUnallocatedFunctionInfo() && 1340b57cec5SDimitry Andric ParentFuncIdPlusOne != FunctionSentinel; 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric unsigned getParentFuncId() const { 1380b57cec5SDimitry Andric assert(isInlinedCallSite()); 1390b57cec5SDimitry Andric return ParentFuncIdPlusOne - 1; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric }; 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric /// Holds state from .cv_file and .cv_loc directives for later emission. 1440b57cec5SDimitry Andric class CodeViewContext { 1450b57cec5SDimitry Andric public: 146*0fca6ea1SDimitry Andric CodeViewContext(MCContext *MCCtx) : MCCtx(MCCtx) {} 1470b57cec5SDimitry Andric ~CodeViewContext(); 1480b57cec5SDimitry Andric 14906c3fb27SDimitry Andric CodeViewContext &operator=(const CodeViewContext &other) = delete; 15006c3fb27SDimitry Andric CodeViewContext(const CodeViewContext &other) = delete; 15106c3fb27SDimitry Andric 1520b57cec5SDimitry Andric bool isValidFileNumber(unsigned FileNumber) const; 1530b57cec5SDimitry Andric bool addFile(MCStreamer &OS, unsigned FileNumber, StringRef Filename, 1540b57cec5SDimitry Andric ArrayRef<uint8_t> ChecksumBytes, uint8_t ChecksumKind); 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric /// Records the function id of a normal function. Returns false if the 1570b57cec5SDimitry Andric /// function id has already been used, and true otherwise. 1580b57cec5SDimitry Andric bool recordFunctionId(unsigned FuncId); 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric /// Records the function id of an inlined call site. Records the "inlined at" 1610b57cec5SDimitry Andric /// location info of the call site, including what function or inlined call 1620b57cec5SDimitry Andric /// site it was inlined into. Returns false if the function id has already 1630b57cec5SDimitry Andric /// been used, and true otherwise. 1640b57cec5SDimitry Andric bool recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc, 1650b57cec5SDimitry Andric unsigned IAFile, unsigned IALine, 1660b57cec5SDimitry Andric unsigned IACol); 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric /// Retreive the function info if this is a valid function id, or nullptr. 1690b57cec5SDimitry Andric MCCVFunctionInfo *getCVFunctionInfo(unsigned FuncId); 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric /// Saves the information from the currently parsed .cv_loc directive 1720b57cec5SDimitry Andric /// and sets CVLocSeen. When the next instruction is assembled an entry 1730b57cec5SDimitry Andric /// in the line number table with this information and the address of the 1740b57cec5SDimitry Andric /// instruction will be created. 1750b57cec5SDimitry Andric void recordCVLoc(MCContext &Ctx, const MCSymbol *Label, unsigned FunctionId, 1760b57cec5SDimitry Andric unsigned FileNo, unsigned Line, unsigned Column, 1770b57cec5SDimitry Andric bool PrologueEnd, bool IsStmt); 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric /// Add a line entry. 1800b57cec5SDimitry Andric void addLineEntry(const MCCVLoc &LineEntry); 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric std::vector<MCCVLoc> getFunctionLineEntries(unsigned FuncId); 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric std::pair<size_t, size_t> getLineExtent(unsigned FuncId); 1855f757f3fSDimitry Andric std::pair<size_t, size_t> getLineExtentIncludingInlinees(unsigned FuncId); 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric ArrayRef<MCCVLoc> getLinesForExtent(size_t L, size_t R); 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric /// Emits a line table substream. 1900b57cec5SDimitry Andric void emitLineTableForFunction(MCObjectStreamer &OS, unsigned FuncId, 1910b57cec5SDimitry Andric const MCSymbol *FuncBegin, 1920b57cec5SDimitry Andric const MCSymbol *FuncEnd); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric void emitInlineLineTableForFunction(MCObjectStreamer &OS, 1950b57cec5SDimitry Andric unsigned PrimaryFunctionId, 1960b57cec5SDimitry Andric unsigned SourceFileId, 1970b57cec5SDimitry Andric unsigned SourceLineNum, 1980b57cec5SDimitry Andric const MCSymbol *FnStartSym, 1990b57cec5SDimitry Andric const MCSymbol *FnEndSym); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric /// Encodes the binary annotations once we have a layout. 202*0fca6ea1SDimitry Andric void encodeInlineLineTable(const MCAssembler &Asm, 2030b57cec5SDimitry Andric MCCVInlineLineTableFragment &F); 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric MCFragment * 2060b57cec5SDimitry Andric emitDefRange(MCObjectStreamer &OS, 2070b57cec5SDimitry Andric ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, 2080b57cec5SDimitry Andric StringRef FixedSizePortion); 2090b57cec5SDimitry Andric 210*0fca6ea1SDimitry Andric void encodeDefRange(const MCAssembler &Asm, MCCVDefRangeFragment &F); 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric /// Emits the string table substream. 2130b57cec5SDimitry Andric void emitStringTable(MCObjectStreamer &OS); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric /// Emits the file checksum substream. 2160b57cec5SDimitry Andric void emitFileChecksums(MCObjectStreamer &OS); 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric /// Emits the offset into the checksum table of the given file number. 2190b57cec5SDimitry Andric void emitFileChecksumOffset(MCObjectStreamer &OS, unsigned FileNo); 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric /// Add something to the string table. Returns the final string as well as 2220b57cec5SDimitry Andric /// offset into the string table. 2230b57cec5SDimitry Andric std::pair<StringRef, unsigned> addToStringTable(StringRef S); 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric private: 226*0fca6ea1SDimitry Andric MCContext *MCCtx; 227*0fca6ea1SDimitry Andric 2280b57cec5SDimitry Andric /// Map from string to string table offset. 2290b57cec5SDimitry Andric StringMap<unsigned> StringTable; 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric /// The fragment that ultimately holds our strings. 2320b57cec5SDimitry Andric MCDataFragment *StrTabFragment = nullptr; 2330b57cec5SDimitry Andric bool InsertedStrTabFragment = false; 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric MCDataFragment *getStringTableFragment(); 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric /// Get a string table offset. 2380b57cec5SDimitry Andric unsigned getStringTableOffset(StringRef S); 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric struct FileInfo { 2410b57cec5SDimitry Andric unsigned StringTableOffset; 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric // Indicates if this FileInfo corresponds to an actual file, or hasn't been 2440b57cec5SDimitry Andric // set yet. 2450b57cec5SDimitry Andric bool Assigned = false; 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric uint8_t ChecksumKind; 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric ArrayRef<uint8_t> Checksum; 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric // Checksum offset stored as a symbol because it might be requested 2520b57cec5SDimitry Andric // before it has been calculated, so a fixup may be needed. 2530b57cec5SDimitry Andric MCSymbol *ChecksumTableOffset; 2540b57cec5SDimitry Andric }; 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric /// Array storing added file information. 2570b57cec5SDimitry Andric SmallVector<FileInfo, 4> Files; 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric /// The offset of the first and last .cv_loc directive for a given function 2600b57cec5SDimitry Andric /// id. 2610b57cec5SDimitry Andric std::map<unsigned, std::pair<size_t, size_t>> MCCVLineStartStop; 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric /// A collection of MCCVLoc for each section. 2640b57cec5SDimitry Andric std::vector<MCCVLoc> MCCVLines; 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric /// All known functions and inlined call sites, indexed by function id. 2670b57cec5SDimitry Andric std::vector<MCCVFunctionInfo> Functions; 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric /// Indicate whether we have already laid out the checksum table addresses or 2700b57cec5SDimitry Andric /// not. 2710b57cec5SDimitry Andric bool ChecksumOffsetsAssigned = false; 2720b57cec5SDimitry Andric }; 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric } // end namespace llvm 2750b57cec5SDimitry Andric #endif 276