Home | History | Annotate | Download | only in MC
      1 //===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // Holds state from .cv_file and .cv_loc directives for later emission.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_MC_MCCODEVIEW_H
     15 #define LLVM_MC_MCCODEVIEW_H
     16 
     17 #include "llvm/ADT/StringMap.h"
     18 #include "llvm/ADT/StringRef.h"
     19 #include "llvm/MC/MCFragment.h"
     20 #include "llvm/MC/MCObjectStreamer.h"
     21 #include <map>
     22 #include <vector>
     23 
     24 namespace llvm {
     25 class MCContext;
     26 class MCObjectStreamer;
     27 class MCStreamer;
     28 class CodeViewContext;
     29 
     30 /// \brief Instances of this class represent the information from a
     31 /// .cv_loc directive.
     32 class MCCVLoc {
     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(unsigned functionid, unsigned fileNum, unsigned line, unsigned column,
     43           bool prologueend, bool isstmt)
     44       : FunctionId(functionid), FileNum(fileNum), Line(line), Column(column),
     45         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   unsigned getFunctionId() const { return FunctionId; }
     52 
     53   /// \brief Get the FileNum of this MCCVLoc.
     54   unsigned getFileNum() const { return FileNum; }
     55 
     56   /// \brief Get the Line of this MCCVLoc.
     57   unsigned getLine() const { return Line; }
     58 
     59   /// \brief Get the Column of this MCCVLoc.
     60   unsigned getColumn() const { return Column; }
     61 
     62   bool isPrologueEnd() const { return PrologueEnd; }
     63   bool isStmt() const { return IsStmt; }
     64 
     65   void setFunctionId(unsigned FID) { FunctionId = FID; }
     66 
     67   /// \brief Set the FileNum of this MCCVLoc.
     68   void setFileNum(unsigned fileNum) { FileNum = fileNum; }
     69 
     70   /// \brief Set the Line of this MCCVLoc.
     71   void setLine(unsigned line) { Line = line; }
     72 
     73   /// \brief Set the Column of this MCCVLoc.
     74   void setColumn(unsigned column) {
     75     assert(column <= UINT16_MAX);
     76     Column = column;
     77   }
     78 
     79   void setPrologueEnd(bool PE) { PrologueEnd = PE; }
     80   void setIsStmt(bool IS) { IsStmt = IS; }
     81 };
     82 
     83 /// \brief Instances of this class represent the line information for
     84 /// the CodeView line table entries.  Which is created after a machine
     85 /// instruction is assembled and uses an address from a temporary label
     86 /// created at the current address in the current section and the info from
     87 /// the last .cv_loc directive seen as stored in the context.
     88 class MCCVLineEntry : public MCCVLoc {
     89   const MCSymbol *Label;
     90 
     91 private:
     92   // Allow the default copy constructor and assignment operator to be used
     93   // for an MCCVLineEntry object.
     94 
     95 public:
     96   // Constructor to create an MCCVLineEntry given a symbol and the dwarf loc.
     97   MCCVLineEntry(const MCSymbol *Label, const MCCVLoc loc)
     98       : MCCVLoc(loc), Label(Label) {}
     99 
    100   const MCSymbol *getLabel() const { return Label; }
    101 
    102   // This is called when an instruction is assembled into the specified
    103   // section and if there is information from the last .cv_loc directive that
    104   // has yet to have a line entry made for it is made.
    105   static void Make(MCObjectStreamer *MCOS);
    106 };
    107 
    108 /// Information describing a function or inlined call site introduced by
    109 /// .cv_func_id or .cv_inline_site_id. Accumulates information from .cv_loc
    110 /// directives used with this function's id or the id of an inlined call site
    111 /// within this function or inlined call site.
    112 struct MCCVFunctionInfo {
    113   /// If this represents an inlined call site, then ParentFuncIdPlusOne will be
    114   /// the parent function id plus one. If this represents a normal function,
    115   /// then there is no parent, and ParentFuncIdPlusOne will be FunctionSentinel.
    116   /// If this struct is an unallocated slot in the function info vector, then
    117   /// ParentFuncIdPlusOne will be zero.
    118   unsigned ParentFuncIdPlusOne = 0;
    119 
    120   enum : unsigned { FunctionSentinel = ~0U };
    121 
    122   struct LineInfo {
    123     unsigned File;
    124     unsigned Line;
    125     unsigned Col;
    126   };
    127 
    128   LineInfo InlinedAt;
    129 
    130   /// The section of the first .cv_loc directive used for this function, or null
    131   /// if none has been seen yet.
    132   MCSection *Section = nullptr;
    133 
    134   /// Map from inlined call site id to the inlined at location to use for that
    135   /// call site. Call chains are collapsed, so for the call chain 'f -> g -> h',
    136   /// the InlinedAtMap of 'f' will contain entries for 'g' and 'h' that both
    137   /// list the line info for the 'g' call site.
    138   DenseMap<unsigned, LineInfo> InlinedAtMap;
    139 
    140   /// Returns true if this is function info has not yet been used in a
    141   /// .cv_func_id or .cv_inline_site_id directive.
    142   bool isUnallocatedFunctionInfo() const { return ParentFuncIdPlusOne == 0; }
    143 
    144   /// Returns true if this represents an inlined call site, meaning
    145   /// ParentFuncIdPlusOne is neither zero nor ~0U.
    146   bool isInlinedCallSite() const {
    147     return !isUnallocatedFunctionInfo() &&
    148            ParentFuncIdPlusOne != FunctionSentinel;
    149   }
    150 
    151   unsigned getParentFuncId() const {
    152     assert(isInlinedCallSite());
    153     return ParentFuncIdPlusOne - 1;
    154   }
    155 };
    156 
    157 /// Holds state from .cv_file and .cv_loc directives for later emission.
    158 class CodeViewContext {
    159 public:
    160   CodeViewContext();
    161   ~CodeViewContext();
    162 
    163   bool isValidFileNumber(unsigned FileNumber) const;
    164   bool addFile(MCStreamer &OS, unsigned FileNumber, StringRef Filename,
    165                ArrayRef<uint8_t> ChecksumBytes, uint8_t ChecksumKind);
    166 
    167   /// Records the function id of a normal function. Returns false if the
    168   /// function id has already been used, and true otherwise.
    169   bool recordFunctionId(unsigned FuncId);
    170 
    171   /// Records the function id of an inlined call site. Records the "inlined at"
    172   /// location info of the call site, including what function or inlined call
    173   /// site it was inlined into. Returns false if the function id has already
    174   /// been used, and true otherwise.
    175   bool recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
    176                                unsigned IAFile, unsigned IALine,
    177                                unsigned IACol);
    178 
    179   /// Retreive the function info if this is a valid function id, or nullptr.
    180   MCCVFunctionInfo *getCVFunctionInfo(unsigned FuncId) {
    181     if (FuncId >= Functions.size())
    182       return nullptr;
    183     if (Functions[FuncId].isUnallocatedFunctionInfo())
    184       return nullptr;
    185     return &Functions[FuncId];
    186   }
    187 
    188   /// Saves the information from the currently parsed .cv_loc directive
    189   /// and sets CVLocSeen.  When the next instruction is assembled an entry
    190   /// in the line number table with this information and the address of the
    191   /// instruction will be created.
    192   void setCurrentCVLoc(unsigned FunctionId, unsigned FileNo, unsigned Line,
    193                        unsigned Column, bool PrologueEnd, bool IsStmt) {
    194     CurrentCVLoc.setFunctionId(FunctionId);
    195     CurrentCVLoc.setFileNum(FileNo);
    196     CurrentCVLoc.setLine(Line);
    197     CurrentCVLoc.setColumn(Column);
    198     CurrentCVLoc.setPrologueEnd(PrologueEnd);
    199     CurrentCVLoc.setIsStmt(IsStmt);
    200     CVLocSeen = true;
    201   }
    202   void clearCVLocSeen() { CVLocSeen = false; }
    203 
    204   bool getCVLocSeen() { return CVLocSeen; }
    205   const MCCVLoc &getCurrentCVLoc() { return CurrentCVLoc; }
    206 
    207   bool isValidCVFileNumber(unsigned FileNumber);
    208 
    209   /// \brief Add a line entry.
    210   void addLineEntry(const MCCVLineEntry &LineEntry) {
    211     size_t Offset = MCCVLines.size();
    212     auto I = MCCVLineStartStop.insert(
    213         {LineEntry.getFunctionId(), {Offset, Offset + 1}});
    214     if (!I.second)
    215       I.first->second.second = Offset + 1;
    216     MCCVLines.push_back(LineEntry);
    217   }
    218 
    219   std::vector<MCCVLineEntry> getFunctionLineEntries(unsigned FuncId) {
    220     std::vector<MCCVLineEntry> FilteredLines;
    221 
    222     auto I = MCCVLineStartStop.find(FuncId);
    223     if (I != MCCVLineStartStop.end())
    224       for (size_t Idx = I->second.first, End = I->second.second; Idx != End;
    225            ++Idx)
    226         if (MCCVLines[Idx].getFunctionId() == FuncId)
    227           FilteredLines.push_back(MCCVLines[Idx]);
    228     return FilteredLines;
    229   }
    230 
    231   std::pair<size_t, size_t> getLineExtent(unsigned FuncId) {
    232     auto I = MCCVLineStartStop.find(FuncId);
    233     // Return an empty extent if there are no cv_locs for this function id.
    234     if (I == MCCVLineStartStop.end())
    235       return {~0ULL, 0};
    236     return I->second;
    237   }
    238 
    239   ArrayRef<MCCVLineEntry> getLinesForExtent(size_t L, size_t R) {
    240     if (R <= L)
    241       return None;
    242     if (L >= MCCVLines.size())
    243       return None;
    244     return makeArrayRef(&MCCVLines[L], R - L);
    245   }
    246 
    247   /// Emits a line table substream.
    248   void emitLineTableForFunction(MCObjectStreamer &OS, unsigned FuncId,
    249                                 const MCSymbol *FuncBegin,
    250                                 const MCSymbol *FuncEnd);
    251 
    252   void emitInlineLineTableForFunction(MCObjectStreamer &OS,
    253                                       unsigned PrimaryFunctionId,
    254                                       unsigned SourceFileId,
    255                                       unsigned SourceLineNum,
    256                                       const MCSymbol *FnStartSym,
    257                                       const MCSymbol *FnEndSym);
    258 
    259   /// Encodes the binary annotations once we have a layout.
    260   void encodeInlineLineTable(MCAsmLayout &Layout,
    261                              MCCVInlineLineTableFragment &F);
    262 
    263   void
    264   emitDefRange(MCObjectStreamer &OS,
    265                ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
    266                StringRef FixedSizePortion);
    267 
    268   void encodeDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &F);
    269 
    270   /// Emits the string table substream.
    271   void emitStringTable(MCObjectStreamer &OS);
    272 
    273   /// Emits the file checksum substream.
    274   void emitFileChecksums(MCObjectStreamer &OS);
    275 
    276   /// Emits the offset into the checksum table of the given file number.
    277   void emitFileChecksumOffset(MCObjectStreamer &OS, unsigned FileNo);
    278 
    279   /// Add something to the string table.  Returns the final string as well as
    280   /// offset into the string table.
    281   std::pair<StringRef, unsigned> addToStringTable(StringRef S);
    282 
    283 private:
    284   /// The current CodeView line information from the last .cv_loc directive.
    285   MCCVLoc CurrentCVLoc = MCCVLoc(0, 0, 0, 0, false, true);
    286   bool CVLocSeen = false;
    287 
    288   /// Map from string to string table offset.
    289   StringMap<unsigned> StringTable;
    290 
    291   /// The fragment that ultimately holds our strings.
    292   MCDataFragment *StrTabFragment = nullptr;
    293   bool InsertedStrTabFragment = false;
    294 
    295   MCDataFragment *getStringTableFragment();
    296 
    297   /// Get a string table offset.
    298   unsigned getStringTableOffset(StringRef S);
    299 
    300   struct FileInfo {
    301     unsigned StringTableOffset;
    302 
    303     // Indicates if this FileInfo corresponds to an actual file, or hasn't been
    304     // set yet.
    305     bool Assigned = false;
    306 
    307     uint8_t ChecksumKind;
    308 
    309     ArrayRef<uint8_t> Checksum;
    310 
    311     // Checksum offset stored as a symbol because it might be requested
    312     // before it has been calculated, so a fixup may be needed.
    313     MCSymbol *ChecksumTableOffset;
    314   };
    315 
    316   /// Array storing added file information.
    317   SmallVector<FileInfo, 4> Files;
    318 
    319   /// The offset of the first and last .cv_loc directive for a given function
    320   /// id.
    321   std::map<unsigned, std::pair<size_t, size_t>> MCCVLineStartStop;
    322 
    323   /// A collection of MCCVLineEntry for each section.
    324   std::vector<MCCVLineEntry> MCCVLines;
    325 
    326   /// All known functions and inlined call sites, indexed by function id.
    327   std::vector<MCCVFunctionInfo> Functions;
    328 
    329   /// Indicate whether we have already laid out the checksum table addresses or
    330   /// not.
    331   bool ChecksumOffsetsAssigned = false;
    332 };
    333 
    334 } // end namespace llvm
    335 #endif
    336