LCOV - code coverage report
Current view: top level - lib/MC - MCCodeView.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 274 286 95.8 %
Date: 2017-09-14 15:23:50 Functions: 19 19 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "llvm/MC/MCCodeView.h"
      15             : #include "llvm/ADT/STLExtras.h"
      16             : #include "llvm/BinaryFormat/COFF.h"
      17             : #include "llvm/DebugInfo/CodeView/CodeView.h"
      18             : #include "llvm/DebugInfo/CodeView/Line.h"
      19             : #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
      20             : #include "llvm/MC/MCAsmLayout.h"
      21             : #include "llvm/MC/MCContext.h"
      22             : #include "llvm/MC/MCObjectStreamer.h"
      23             : #include "llvm/MC/MCValue.h"
      24             : #include "llvm/Support/EndianStream.h"
      25             : 
      26             : using namespace llvm;
      27             : using namespace llvm::codeview;
      28             : 
      29       26103 : CodeViewContext::CodeViewContext() {}
      30             : 
      31       18565 : CodeViewContext::~CodeViewContext() {
      32             :   // If someone inserted strings into the string table but never actually
      33             :   // emitted them somewhere, clean up the fragment.
      34        3713 :   if (!InsertedStrTabFragment)
      35        3692 :     delete StrTabFragment;
      36        3713 : }
      37             : 
      38             : /// This is a valid number for use with .cv_loc if we've already seen a .cv_file
      39             : /// for it.
      40          91 : bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const {
      41          91 :   unsigned Idx = FileNumber - 1;
      42         182 :   if (Idx < Filenames.size())
      43         270 :     return !Filenames[Idx].empty();
      44             :   return false;
      45             : }
      46             : 
      47         111 : bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) {
      48             :   assert(FileNumber > 0);
      49         111 :   Filename = addToStringTable(Filename);
      50         111 :   unsigned Idx = FileNumber - 1;
      51         222 :   if (Idx >= Filenames.size())
      52         111 :     Filenames.resize(Idx + 1);
      53             : 
      54         111 :   if (Filename.empty())
      55           0 :     Filename = "<stdin>";
      56             : 
      57         333 :   if (!Filenames[Idx].empty())
      58             :     return false;
      59             : 
      60             :   // FIXME: We should store the string table offset of the filename, rather than
      61             :   // the filename itself for efficiency.
      62         111 :   Filename = addToStringTable(Filename);
      63             : 
      64         222 :   Filenames[Idx] = Filename;
      65         111 :   return true;
      66             : }
      67             : 
      68         155 : bool CodeViewContext::recordFunctionId(unsigned FuncId) {
      69         310 :   if (FuncId >= Functions.size())
      70         155 :     Functions.resize(FuncId + 1);
      71             : 
      72             :   // Return false if this function info was already allocated.
      73         310 :   if (!Functions[FuncId].isUnallocatedFunctionInfo())
      74             :     return false;
      75             : 
      76             :   // Mark this as an allocated normal function, and leave the rest alone.
      77         155 :   Functions[FuncId].ParentFuncIdPlusOne = MCCVFunctionInfo::FunctionSentinel;
      78         155 :   return true;
      79             : }
      80             : 
      81          31 : bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
      82             :                                               unsigned IAFile, unsigned IALine,
      83             :                                               unsigned IACol) {
      84          62 :   if (FuncId >= Functions.size())
      85          30 :     Functions.resize(FuncId + 1);
      86             : 
      87             :   // Return false if this function info was already allocated.
      88          62 :   if (!Functions[FuncId].isUnallocatedFunctionInfo())
      89             :     return false;
      90             : 
      91             :   MCCVFunctionInfo::LineInfo InlinedAt;
      92          30 :   InlinedAt.File = IAFile;
      93          30 :   InlinedAt.Line = IALine;
      94          30 :   InlinedAt.Col = IACol;
      95             : 
      96             :   // Mark this as an inlined call site and record call site line info.
      97          30 :   MCCVFunctionInfo *Info = &Functions[FuncId];
      98          30 :   Info->ParentFuncIdPlusOne = IAFunc + 1;
      99          30 :   Info->InlinedAt = InlinedAt;
     100             : 
     101             :   // Walk up the call chain adding this function id to the InlinedAtMap of all
     102             :   // transitive callers until we hit a real function.
     103          76 :   while (Info->isInlinedCallSite()) {
     104          38 :     InlinedAt = Info->InlinedAt;
     105         114 :     Info = getCVFunctionInfo(Info->getParentFuncId());
     106          76 :     Info->InlinedAtMap[FuncId] = InlinedAt;
     107             :   }
     108             : 
     109             :   return true;
     110             : }
     111             : 
     112         288 : MCDataFragment *CodeViewContext::getStringTableFragment() {
     113         288 :   if (!StrTabFragment) {
     114         222 :     StrTabFragment = new MCDataFragment();
     115             :     // Start a new string table out with a null byte.
     116         111 :     StrTabFragment->getContents().push_back('\0');
     117             :   }
     118         288 :   return StrTabFragment;
     119             : }
     120             : 
     121         222 : StringRef CodeViewContext::addToStringTable(StringRef S) {
     122         444 :   SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents();
     123             :   auto Insertion =
     124         888 :       StringTable.insert(std::make_pair(S, unsigned(Contents.size())));
     125             :   // Return the string from the table, since it is stable.
     126         444 :   S = Insertion.first->first();
     127         222 :   if (Insertion.second) {
     128             :     // The string map key is always null terminated.
     129         111 :     Contents.append(S.begin(), S.end() + 1);
     130             :   }
     131         222 :   return S;
     132             : }
     133             : 
     134          59 : unsigned CodeViewContext::getStringTableOffset(StringRef S) {
     135             :   // A string table offset of zero is always the empty string.
     136          59 :   if (S.empty())
     137             :     return 0;
     138          59 :   auto I = StringTable.find(S);
     139             :   assert(I != StringTable.end());
     140          59 :   return I->second;
     141             : }
     142             : 
     143          66 : void CodeViewContext::emitStringTable(MCObjectStreamer &OS) {
     144          66 :   MCContext &Ctx = OS.getContext();
     145          66 :   MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin", false),
     146          66 :            *StringEnd = Ctx.createTempSymbol("strtab_end", false);
     147             : 
     148          66 :   OS.EmitIntValue(unsigned(DebugSubsectionKind::StringTable), 4);
     149          66 :   OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4);
     150          66 :   OS.EmitLabel(StringBegin);
     151             : 
     152             :   // Put the string table data fragment here, if we haven't already put it
     153             :   // somewhere else. If somebody wants two string tables in their .s file, one
     154             :   // will just be empty.
     155          66 :   if (!InsertedStrTabFragment) {
     156          66 :     OS.insert(getStringTableFragment());
     157          66 :     InsertedStrTabFragment = true;
     158             :   }
     159             : 
     160          66 :   OS.EmitValueToAlignment(4, 0);
     161             : 
     162          66 :   OS.EmitLabel(StringEnd);
     163          66 : }
     164             : 
     165          66 : void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) {
     166             :   // Do nothing if there are no file checksums. Microsoft's linker rejects empty
     167             :   // CodeView substreams.
     168          66 :   if (Filenames.empty())
     169             :     return;
     170             : 
     171          52 :   MCContext &Ctx = OS.getContext();
     172          52 :   MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin", false),
     173          52 :            *FileEnd = Ctx.createTempSymbol("filechecksums_end", false);
     174             : 
     175          52 :   OS.EmitIntValue(unsigned(DebugSubsectionKind::FileChecksums), 4);
     176          52 :   OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4);
     177          52 :   OS.EmitLabel(FileBegin);
     178             : 
     179             :   // Emit an array of FileChecksum entries. We index into this table using the
     180             :   // user-provided file number. Each entry is currently 8 bytes, as we don't
     181             :   // emit checksums.
     182         215 :   for (StringRef Filename : Filenames) {
     183          59 :     OS.EmitIntValue(getStringTableOffset(Filename), 4);
     184             :     // Zero the next two fields and align back to 4 bytes. This indicates that
     185             :     // no checksum is present.
     186          59 :     OS.EmitIntValue(0, 4);
     187             :   }
     188             : 
     189          52 :   OS.EmitLabel(FileEnd);
     190             : }
     191             : 
     192          92 : void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS,
     193             :                                                unsigned FuncId,
     194             :                                                const MCSymbol *FuncBegin,
     195             :                                                const MCSymbol *FuncEnd) {
     196          92 :   MCContext &Ctx = OS.getContext();
     197          92 :   MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin", false),
     198          92 :            *LineEnd = Ctx.createTempSymbol("linetable_end", false);
     199             : 
     200          92 :   OS.EmitIntValue(unsigned(DebugSubsectionKind::Lines), 4);
     201          92 :   OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4);
     202          92 :   OS.EmitLabel(LineBegin);
     203          92 :   OS.EmitCOFFSecRel32(FuncBegin, /*Offset=*/0);
     204          92 :   OS.EmitCOFFSectionIndex(FuncBegin);
     205             : 
     206             :   // Actual line info.
     207         184 :   std::vector<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId);
     208             :   bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) {
     209         167 :     return LineEntry.getColumn() != 0;
     210         184 :   });
     211          92 :   OS.EmitIntValue(HaveColumns ? int(LF_HaveColumns) : 0, 2);
     212          92 :   OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4);
     213             : 
     214         373 :   for (auto I = Locs.begin(), E = Locs.end(); I != E;) {
     215             :     // Emit a file segment for the run of locations that share a file id.
     216          97 :     unsigned CurFileNum = I->getFileNum();
     217             :     auto FileSegEnd =
     218             :         std::find_if(I, E, [CurFileNum](const MCCVLineEntry &Loc) {
     219         300 :           return Loc.getFileNum() != CurFileNum;
     220          97 :         });
     221          97 :     unsigned EntryCount = FileSegEnd - I;
     222         582 :     OS.AddComment("Segment for file '" + Twine(Filenames[CurFileNum - 1]) +
     223         291 :                   "' begins");
     224          97 :     OS.EmitIntValue(8 * (CurFileNum - 1), 4);
     225          97 :     OS.EmitIntValue(EntryCount, 4);
     226          97 :     uint32_t SegmentSize = 12;
     227          97 :     SegmentSize += 8 * EntryCount;
     228          97 :     if (HaveColumns)
     229          74 :       SegmentSize += 4 * EntryCount;
     230          97 :     OS.EmitIntValue(SegmentSize, 4);
     231             : 
     232         486 :     for (auto J = I; J != FileSegEnd; ++J) {
     233         292 :       OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4);
     234         292 :       unsigned LineData = J->getLine();
     235         584 :       if (J->isStmt())
     236           1 :         LineData |= LineInfo::StatementFlag;
     237         292 :       OS.EmitIntValue(LineData, 4);
     238             :     }
     239          97 :     if (HaveColumns) {
     240         326 :       for (auto J = I; J != FileSegEnd; ++J) {
     241         252 :         OS.EmitIntValue(J->getColumn(), 2);
     242         252 :         OS.EmitIntValue(0, 2);
     243             :       }
     244             :     }
     245             :     I = FileSegEnd;
     246             :   }
     247          92 :   OS.EmitLabel(LineEnd);
     248          92 : }
     249             : 
     250         426 : static bool compressAnnotation(uint32_t Data, SmallVectorImpl<char> &Buffer) {
     251         426 :   if (isUInt<7>(Data)) {
     252         426 :     Buffer.push_back(Data);
     253         426 :     return true;
     254             :   }
     255             : 
     256           0 :   if (isUInt<14>(Data)) {
     257           0 :     Buffer.push_back((Data >> 8) | 0x80);
     258           0 :     Buffer.push_back(Data & 0xff);
     259           0 :     return true;
     260             :   }
     261             : 
     262           0 :   if (isUInt<29>(Data)) {
     263           0 :     Buffer.push_back((Data >> 24) | 0xC0);
     264           0 :     Buffer.push_back((Data >> 16) & 0xff);
     265           0 :     Buffer.push_back((Data >> 8) & 0xff);
     266           0 :     Buffer.push_back(Data & 0xff);
     267           0 :     return true;
     268             :   }
     269             : 
     270             :   return false;
     271             : }
     272             : 
     273             : static bool compressAnnotation(BinaryAnnotationsOpCode Annotation,
     274             :                                SmallVectorImpl<char> &Buffer) {
     275         213 :   return compressAnnotation(static_cast<uint32_t>(Annotation), Buffer);
     276             : }
     277             : 
     278             : static uint32_t encodeSignedNumber(uint32_t Data) {
     279         123 :   if (Data >> 31)
     280           3 :     return ((-Data) << 1) | 1;
     281         120 :   return Data << 1;
     282             : }
     283             : 
     284          22 : void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS,
     285             :                                                      unsigned PrimaryFunctionId,
     286             :                                                      unsigned SourceFileId,
     287             :                                                      unsigned SourceLineNum,
     288             :                                                      const MCSymbol *FnStartSym,
     289             :                                                      const MCSymbol *FnEndSym) {
     290             :   // Create and insert a fragment into the current section that will be encoded
     291             :   // later.
     292             :   new MCCVInlineLineTableFragment(PrimaryFunctionId, SourceFileId,
     293             :                                   SourceLineNum, FnStartSym, FnEndSym,
     294          66 :                                   OS.getCurrentSectionOnly());
     295          22 : }
     296             : 
     297         106 : void CodeViewContext::emitDefRange(
     298             :     MCObjectStreamer &OS,
     299             :     ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
     300             :     StringRef FixedSizePortion) {
     301             :   // Create and insert a fragment into the current section that will be encoded
     302             :   // later.
     303         212 :   new MCCVDefRangeFragment(Ranges, FixedSizePortion,
     304         212 :                            OS.getCurrentSectionOnly());
     305         106 : }
     306             : 
     307         591 : static unsigned computeLabelDiff(MCAsmLayout &Layout, const MCSymbol *Begin,
     308             :                                  const MCSymbol *End) {
     309         591 :   MCContext &Ctx = Layout.getAssembler().getContext();
     310         591 :   MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
     311         591 :   const MCExpr *BeginRef = MCSymbolRefExpr::create(Begin, Variant, Ctx),
     312         591 :                *EndRef = MCSymbolRefExpr::create(End, Variant, Ctx);
     313             :   const MCExpr *AddrDelta =
     314         591 :       MCBinaryExpr::create(MCBinaryExpr::Sub, EndRef, BeginRef, Ctx);
     315             :   int64_t Result;
     316         591 :   bool Success = AddrDelta->evaluateKnownAbsolute(Result, Layout);
     317             :   assert(Success && "failed to evaluate label difference as absolute");
     318             :   (void)Success;
     319             :   assert(Result >= 0 && "negative label difference requested");
     320             :   assert(Result < UINT_MAX && "label difference greater than 2GB");
     321         591 :   return unsigned(Result);
     322             : }
     323             : 
     324          66 : void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
     325             :                                             MCCVInlineLineTableFragment &Frag) {
     326             :   size_t LocBegin;
     327             :   size_t LocEnd;
     328         198 :   std::tie(LocBegin, LocEnd) = getLineExtent(Frag.SiteFuncId);
     329             : 
     330             :   // Include all child inline call sites in our .cv_loc extent.
     331         132 :   MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId);
     332         216 :   for (auto &KV : SiteInfo->InlinedAtMap) {
     333          18 :     unsigned ChildId = KV.first;
     334          18 :     auto Extent = getLineExtent(ChildId);
     335          18 :     LocBegin = std::min(LocBegin, Extent.first);
     336          18 :     LocEnd = std::max(LocEnd, Extent.second);
     337             :   }
     338             : 
     339          66 :   if (LocBegin >= LocEnd)
     340           0 :     return;
     341         132 :   ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd);
     342          66 :   if (Locs.empty())
     343             :     return;
     344             : 
     345             :   // Make an artificial start location using the function start and the inlinee
     346             :   // lines start location information. All deltas start relative to this
     347             :   // location.
     348         132 :   MCCVLineEntry StartLoc(Frag.getFnStartSym(), MCCVLoc(Locs.front()));
     349         132 :   StartLoc.setFileNum(Frag.StartFileId);
     350         132 :   StartLoc.setLine(Frag.StartLineNum);
     351          66 :   bool HaveOpenRange = false;
     352             : 
     353          66 :   const MCSymbol *LastLabel = Frag.getFnStartSym();
     354             :   MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc;
     355          66 :   LastSourceLoc.File = Frag.StartFileId;
     356          66 :   LastSourceLoc.Line = Frag.StartLineNum;
     357             : 
     358          66 :   SmallVectorImpl<char> &Buffer = Frag.getContents();
     359          66 :   Buffer.clear(); // Clear old contents if we went through relaxation.
     360         279 :   for (const MCCVLineEntry &Loc : Locs) {
     361             :     // Exit early if our line table would produce an oversized InlineSiteSym
     362             :     // record. Account for the ChangeCodeLength annotation emitted after the
     363             :     // loop ends.
     364         147 :     constexpr uint32_t InlineSiteSize = 12;
     365         147 :     constexpr uint32_t AnnotationSize = 8;
     366         147 :     size_t MaxBufferSize = MaxRecordLength - InlineSiteSize - AnnotationSize;
     367         294 :     if (Buffer.size() >= MaxBufferSize)
     368             :       break;
     369             : 
     370         147 :     if (Loc.getFunctionId() == Frag.SiteFuncId) {
     371         108 :       CurSourceLoc.File = Loc.getFileNum();
     372         108 :       CurSourceLoc.Line = Loc.getLine();
     373             :     } else {
     374          39 :       auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId());
     375         117 :       if (I != SiteInfo->InlinedAtMap.end()) {
     376             :         // This .cv_loc is from a child inline call site. Use the source
     377             :         // location of the inlined call site instead of the .cv_loc directive
     378             :         // source location.
     379          33 :         CurSourceLoc = I->second;
     380             :       } else {
     381             :         // We've hit a cv_loc not attributed to this inline call site. Use this
     382             :         // label to end the PC range.
     383           6 :         if (HaveOpenRange) {
     384           3 :           unsigned Length = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
     385           3 :           compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
     386           3 :           compressAnnotation(Length, Buffer);
     387           3 :           LastLabel = Loc.getLabel();
     388             :         }
     389           6 :         HaveOpenRange = false;
     390           6 :         continue;
     391             :       }
     392             :     }
     393             : 
     394             :     // Skip this .cv_loc if we have an open range and this isn't a meaningful
     395             :     // source location update. The current table format does not support column
     396             :     // info, so we can skip updates for those.
     397         141 :     if (HaveOpenRange && CurSourceLoc.File == LastSourceLoc.File &&
     398             :         CurSourceLoc.Line == LastSourceLoc.Line)
     399          18 :       continue;
     400             : 
     401         123 :     HaveOpenRange = true;
     402             : 
     403         123 :     if (CurSourceLoc.File != LastSourceLoc.File) {
     404             :       // File ids are 1 based, and each file checksum table entry is 8 bytes
     405             :       // long. See emitFileChecksums above.
     406           6 :       unsigned FileOffset = 8 * (CurSourceLoc.File - 1);
     407           6 :       compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer);
     408           6 :       compressAnnotation(FileOffset, Buffer);
     409             :     }
     410             : 
     411         123 :     int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line;
     412         246 :     unsigned EncodedLineDelta = encodeSignedNumber(LineDelta);
     413         123 :     unsigned CodeDelta = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
     414         123 :     if (CodeDelta == 0 && LineDelta != 0) {
     415          12 :       compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
     416          12 :       compressAnnotation(EncodedLineDelta, Buffer);
     417         111 :     } else if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) {
     418             :       // The ChangeCodeOffsetAndLineOffset combination opcode is used when the
     419             :       // encoded line delta uses 3 or fewer set bits and the code offset fits
     420             :       // in one nibble.
     421          90 :       unsigned Operand = (EncodedLineDelta << 4) | CodeDelta;
     422          90 :       compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset,
     423             :                          Buffer);
     424          90 :       compressAnnotation(Operand, Buffer);
     425             :     } else {
     426             :       // Otherwise use the separate line and code deltas.
     427          21 :       if (LineDelta != 0) {
     428          15 :         compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
     429          15 :         compressAnnotation(EncodedLineDelta, Buffer);
     430             :       }
     431          21 :       compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffset, Buffer);
     432          21 :       compressAnnotation(CodeDelta, Buffer);
     433             :     }
     434             : 
     435         123 :     LastLabel = Loc.getLabel();
     436         123 :     LastSourceLoc = CurSourceLoc;
     437             :   }
     438             : 
     439             :   assert(HaveOpenRange);
     440             : 
     441             :   unsigned EndSymLength =
     442          66 :       computeLabelDiff(Layout, LastLabel, Frag.getFnEndSym());
     443          66 :   unsigned LocAfterLength = ~0U;
     444         132 :   ArrayRef<MCCVLineEntry> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1);
     445          66 :   if (!LocAfter.empty()) {
     446             :     // Only try to compute this difference if we're in the same section.
     447          54 :     const MCCVLineEntry &Loc = LocAfter[0];
     448         162 :     if (&Loc.getLabel()->getSection(false) == &LastLabel->getSection(false))
     449          51 :       LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
     450             :   }
     451             : 
     452          66 :   compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
     453          66 :   compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer);
     454             : }
     455             : 
     456         318 : void CodeViewContext::encodeDefRange(MCAsmLayout &Layout,
     457             :                                      MCCVDefRangeFragment &Frag) {
     458         318 :   MCContext &Ctx = Layout.getAssembler().getContext();
     459         636 :   SmallVectorImpl<char> &Contents = Frag.getContents();
     460         318 :   Contents.clear();
     461         318 :   SmallVectorImpl<MCFixup> &Fixups = Frag.getFixups();
     462         318 :   Fixups.clear();
     463         636 :   raw_svector_ostream OS(Contents);
     464             : 
     465             :   // Compute all the sizes up front.
     466         636 :   SmallVector<std::pair<unsigned, unsigned>, 4> GapAndRangeSizes;
     467         318 :   const MCSymbol *LastLabel = nullptr;
     468         969 :   for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) {
     469             :     unsigned GapSize =
     470         333 :         LastLabel ? computeLabelDiff(Layout, LastLabel, Range.first) : 0;
     471         333 :     unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second);
     472         333 :     GapAndRangeSizes.push_back({GapSize, RangeSize});
     473         333 :     LastLabel = Range.second;
     474             :   }
     475             : 
     476             :   // Write down each range where the variable is defined.
     477         960 :   for (size_t I = 0, E = Frag.getRanges().size(); I != E;) {
     478             :     // If the range size of multiple consecutive ranges is under the max,
     479             :     // combine the ranges and emit some gaps.
     480         648 :     const MCSymbol *RangeBegin = Frag.getRanges()[I].first;
     481         324 :     unsigned RangeSize = GapAndRangeSizes[I].second;
     482         324 :     size_t J = I + 1;
     483         342 :     for (; J != E; ++J) {
     484          30 :       unsigned GapAndRangeSize = GapAndRangeSizes[J].first + GapAndRangeSizes[J].second;
     485          15 :       if (RangeSize + GapAndRangeSize > MaxDefRange)
     486             :         break;
     487           9 :       RangeSize += GapAndRangeSize;
     488             :     }
     489         324 :     unsigned NumGaps = J - I - 1;
     490             : 
     491         324 :     support::endian::Writer<support::little> LEWriter(OS);
     492             : 
     493         324 :     unsigned Bias = 0;
     494             :     // We must split the range into chunks of MaxDefRange, this is a fundamental
     495             :     // limitation of the file format.
     496             :     do {
     497         648 :       uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize);
     498             : 
     499         324 :       const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(RangeBegin, Ctx);
     500             :       const MCBinaryExpr *BE =
     501         648 :           MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx);
     502         324 :       MCValue Res;
     503         324 :       BE->evaluateAsRelocatable(Res, &Layout, /*Fixup=*/nullptr);
     504             : 
     505             :       // Each record begins with a 2-byte number indicating how large the record
     506             :       // is.
     507         324 :       StringRef FixedSizePortion = Frag.getFixedSizePortion();
     508             :       // Our record is a fixed sized prefix and a LocalVariableAddrRange that we
     509             :       // are artificially constructing.
     510         324 :       size_t RecordSize = FixedSizePortion.size() +
     511         324 :                           sizeof(LocalVariableAddrRange) + 4 * NumGaps;
     512             :       // Write out the record size.
     513         648 :       LEWriter.write<uint16_t>(RecordSize);
     514             :       // Write out the fixed size prefix.
     515         324 :       OS << FixedSizePortion;
     516             :       // Make space for a fixup that will eventually have a section relative
     517             :       // relocation pointing at the offset where the variable becomes live.
     518         972 :       Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4));
     519         324 :       LEWriter.write<uint32_t>(0); // Fixup for code start.
     520             :       // Make space for a fixup that will record the section index for the code.
     521         972 :       Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2));
     522         324 :       LEWriter.write<uint16_t>(0); // Fixup for section index.
     523             :       // Write down the range's extent.
     524         648 :       LEWriter.write<uint16_t>(Chunk);
     525             : 
     526             :       // Move on to the next range.
     527         324 :       Bias += Chunk;
     528         324 :       RangeSize -= Chunk;
     529         324 :     } while (RangeSize > 0);
     530             : 
     531             :     // Emit the gaps afterwards.
     532             :     assert((NumGaps == 0 || Bias <= MaxDefRange) &&
     533             :            "large ranges should not have gaps");
     534         324 :     unsigned GapStartOffset = GapAndRangeSizes[I].second;
     535         333 :     for (++I; I != J; ++I) {
     536             :       unsigned GapSize, RangeSize;
     537             :       assert(I < GapAndRangeSizes.size());
     538          27 :       std::tie(GapSize, RangeSize) = GapAndRangeSizes[I];
     539          18 :       LEWriter.write<uint16_t>(GapStartOffset);
     540          18 :       LEWriter.write<uint16_t>(GapSize);
     541           9 :       GapStartOffset += GapSize + RangeSize;
     542             :     }
     543             :   }
     544         318 : }
     545             : 
     546             : //
     547             : // This is called when an instruction is assembled into the specified section
     548             : // and if there is information from the last .cv_loc directive that has yet to have
     549             : // a line entry made for it is made.
     550             : //
     551     8336194 : void MCCVLineEntry::Make(MCObjectStreamer *MCOS) {
     552     8336194 :   CodeViewContext &CVC = MCOS->getContext().getCVContext();
     553     8336195 :   if (!CVC.getCVLocSeen())
     554     8335865 :     return;
     555             : 
     556             :   // Create a symbol at in the current section for use in the line entry.
     557         330 :   MCSymbol *LineSym = MCOS->getContext().createTempSymbol();
     558             :   // Set the value of the symbol to use for the MCCVLineEntry.
     559         330 :   MCOS->EmitLabel(LineSym);
     560             : 
     561             :   // Get the current .loc info saved in the context.
     562         330 :   const MCCVLoc &CVLoc = CVC.getCurrentCVLoc();
     563             : 
     564             :   // Create a (local) line entry with the symbol and the current .loc info.
     565         330 :   MCCVLineEntry LineEntry(LineSym, CVLoc);
     566             : 
     567             :   // clear CVLocSeen saying the current .loc info is now used.
     568         330 :   CVC.clearCVLocSeen();
     569             : 
     570             :   // Add the line entry to this section's entries.
     571         330 :   CVC.addLineEntry(LineEntry);
     572             : }

Generated by: LCOV version 1.13