Home | History | Annotate | Line # | Download | only in MC
      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;
     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:
     51   const MCSymbol *getLabel() const { return Label; }
     52 
     53   unsigned getFunctionId() const { return FunctionId; }
     54 
     55   /// Get the FileNum of this MCCVLoc.
     56   unsigned getFileNum() const { return FileNum; }
     57 
     58   /// Get the Line of this MCCVLoc.
     59   unsigned getLine() const { return Line; }
     60 
     61   /// Get the Column of this MCCVLoc.
     62   unsigned getColumn() const { return Column; }
     63 
     64   bool isPrologueEnd() const { return PrologueEnd; }
     65   bool isStmt() const { return IsStmt; }
     66 
     67   void setLabel(const MCSymbol *L) { Label = L; }
     68 
     69   void setFunctionId(unsigned FID) { FunctionId = FID; }
     70 
     71   /// Set the FileNum of this MCCVLoc.
     72   void setFileNum(unsigned fileNum) { FileNum = fileNum; }
     73 
     74   /// Set the Line of this MCCVLoc.
     75   void setLine(unsigned line) { Line = line; }
     76 
     77   /// Set the Column of this MCCVLoc.
     78   void setColumn(unsigned column) {
     79     assert(column <= UINT16_MAX);
     80     Column = column;
     81   }
     82 
     83   void setPrologueEnd(bool PE) { PrologueEnd = PE; }
     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.
    121   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.
    125   bool isInlinedCallSite() const {
    126     return !isUnallocatedFunctionInfo() &&
    127            ParentFuncIdPlusOne != FunctionSentinel;
    128   }
    129 
    130   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