xref: /freebsd-src/contrib/llvm-project/llvm/lib/MC/MCCodeView.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 #include "llvm/MC/MCCodeView.h"
140b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
150b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
160b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/CodeView.h"
170b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/Line.h"
180b57cec5SDimitry Andric #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
1981ad6265SDimitry Andric #include "llvm/MC/MCAssembler.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCObjectStreamer.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCValue.h"
230b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric using namespace llvm::codeview;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric CodeViewContext::~CodeViewContext() {
290b57cec5SDimitry Andric   // If someone inserted strings into the string table but never actually
300b57cec5SDimitry Andric   // emitted them somewhere, clean up the fragment.
31*0fca6ea1SDimitry Andric   if (!InsertedStrTabFragment && StrTabFragment)
32*0fca6ea1SDimitry Andric     StrTabFragment->destroy();
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric /// This is a valid number for use with .cv_loc if we've already seen a .cv_file
360b57cec5SDimitry Andric /// for it.
370b57cec5SDimitry Andric bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const {
380b57cec5SDimitry Andric   unsigned Idx = FileNumber - 1;
390b57cec5SDimitry Andric   if (Idx < Files.size())
400b57cec5SDimitry Andric     return Files[Idx].Assigned;
410b57cec5SDimitry Andric   return false;
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric bool CodeViewContext::addFile(MCStreamer &OS, unsigned FileNumber,
450b57cec5SDimitry Andric                               StringRef Filename,
460b57cec5SDimitry Andric                               ArrayRef<uint8_t> ChecksumBytes,
470b57cec5SDimitry Andric                               uint8_t ChecksumKind) {
480b57cec5SDimitry Andric   assert(FileNumber > 0);
490b57cec5SDimitry Andric   auto FilenameOffset = addToStringTable(Filename);
500b57cec5SDimitry Andric   Filename = FilenameOffset.first;
510b57cec5SDimitry Andric   unsigned Idx = FileNumber - 1;
520b57cec5SDimitry Andric   if (Idx >= Files.size())
530b57cec5SDimitry Andric     Files.resize(Idx + 1);
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   if (Filename.empty())
560b57cec5SDimitry Andric     Filename = "<stdin>";
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   if (Files[Idx].Assigned)
590b57cec5SDimitry Andric     return false;
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   FilenameOffset = addToStringTable(Filename);
620b57cec5SDimitry Andric   Filename = FilenameOffset.first;
630b57cec5SDimitry Andric   unsigned Offset = FilenameOffset.second;
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   auto ChecksumOffsetSymbol =
660b57cec5SDimitry Andric       OS.getContext().createTempSymbol("checksum_offset", false);
670b57cec5SDimitry Andric   Files[Idx].StringTableOffset = Offset;
680b57cec5SDimitry Andric   Files[Idx].ChecksumTableOffset = ChecksumOffsetSymbol;
690b57cec5SDimitry Andric   Files[Idx].Assigned = true;
700b57cec5SDimitry Andric   Files[Idx].Checksum = ChecksumBytes;
710b57cec5SDimitry Andric   Files[Idx].ChecksumKind = ChecksumKind;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   return true;
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric MCCVFunctionInfo *CodeViewContext::getCVFunctionInfo(unsigned FuncId) {
770b57cec5SDimitry Andric   if (FuncId >= Functions.size())
780b57cec5SDimitry Andric     return nullptr;
790b57cec5SDimitry Andric   if (Functions[FuncId].isUnallocatedFunctionInfo())
800b57cec5SDimitry Andric     return nullptr;
810b57cec5SDimitry Andric   return &Functions[FuncId];
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric bool CodeViewContext::recordFunctionId(unsigned FuncId) {
850b57cec5SDimitry Andric   if (FuncId >= Functions.size())
860b57cec5SDimitry Andric     Functions.resize(FuncId + 1);
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric   // Return false if this function info was already allocated.
890b57cec5SDimitry Andric   if (!Functions[FuncId].isUnallocatedFunctionInfo())
900b57cec5SDimitry Andric     return false;
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   // Mark this as an allocated normal function, and leave the rest alone.
930b57cec5SDimitry Andric   Functions[FuncId].ParentFuncIdPlusOne = MCCVFunctionInfo::FunctionSentinel;
940b57cec5SDimitry Andric   return true;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
980b57cec5SDimitry Andric                                               unsigned IAFile, unsigned IALine,
990b57cec5SDimitry Andric                                               unsigned IACol) {
1000b57cec5SDimitry Andric   if (FuncId >= Functions.size())
1010b57cec5SDimitry Andric     Functions.resize(FuncId + 1);
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric   // Return false if this function info was already allocated.
1040b57cec5SDimitry Andric   if (!Functions[FuncId].isUnallocatedFunctionInfo())
1050b57cec5SDimitry Andric     return false;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   MCCVFunctionInfo::LineInfo InlinedAt;
1080b57cec5SDimitry Andric   InlinedAt.File = IAFile;
1090b57cec5SDimitry Andric   InlinedAt.Line = IALine;
1100b57cec5SDimitry Andric   InlinedAt.Col = IACol;
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   // Mark this as an inlined call site and record call site line info.
1130b57cec5SDimitry Andric   MCCVFunctionInfo *Info = &Functions[FuncId];
1140b57cec5SDimitry Andric   Info->ParentFuncIdPlusOne = IAFunc + 1;
1150b57cec5SDimitry Andric   Info->InlinedAt = InlinedAt;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   // Walk up the call chain adding this function id to the InlinedAtMap of all
1180b57cec5SDimitry Andric   // transitive callers until we hit a real function.
1190b57cec5SDimitry Andric   while (Info->isInlinedCallSite()) {
1200b57cec5SDimitry Andric     InlinedAt = Info->InlinedAt;
1210b57cec5SDimitry Andric     Info = getCVFunctionInfo(Info->getParentFuncId());
1220b57cec5SDimitry Andric     Info->InlinedAtMap[FuncId] = InlinedAt;
1230b57cec5SDimitry Andric   }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   return true;
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric void CodeViewContext::recordCVLoc(MCContext &Ctx, const MCSymbol *Label,
1290b57cec5SDimitry Andric                                   unsigned FunctionId, unsigned FileNo,
1300b57cec5SDimitry Andric                                   unsigned Line, unsigned Column,
1310b57cec5SDimitry Andric                                   bool PrologueEnd, bool IsStmt) {
1320b57cec5SDimitry Andric   addLineEntry(MCCVLoc{
1330b57cec5SDimitry Andric       Label, FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt});
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric MCDataFragment *CodeViewContext::getStringTableFragment() {
1370b57cec5SDimitry Andric   if (!StrTabFragment) {
138*0fca6ea1SDimitry Andric     StrTabFragment = MCCtx->allocFragment<MCDataFragment>();
1390b57cec5SDimitry Andric     // Start a new string table out with a null byte.
1400b57cec5SDimitry Andric     StrTabFragment->getContents().push_back('\0');
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric   return StrTabFragment;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric std::pair<StringRef, unsigned> CodeViewContext::addToStringTable(StringRef S) {
1460b57cec5SDimitry Andric   SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents();
1470b57cec5SDimitry Andric   auto Insertion =
1480b57cec5SDimitry Andric       StringTable.insert(std::make_pair(S, unsigned(Contents.size())));
1490b57cec5SDimitry Andric   // Return the string from the table, since it is stable.
1500b57cec5SDimitry Andric   std::pair<StringRef, unsigned> Ret =
1510b57cec5SDimitry Andric       std::make_pair(Insertion.first->first(), Insertion.first->second);
1520b57cec5SDimitry Andric   if (Insertion.second) {
1530b57cec5SDimitry Andric     // The string map key is always null terminated.
1540b57cec5SDimitry Andric     Contents.append(Ret.first.begin(), Ret.first.end() + 1);
1550b57cec5SDimitry Andric   }
1560b57cec5SDimitry Andric   return Ret;
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric unsigned CodeViewContext::getStringTableOffset(StringRef S) {
1600b57cec5SDimitry Andric   // A string table offset of zero is always the empty string.
1610b57cec5SDimitry Andric   if (S.empty())
1620b57cec5SDimitry Andric     return 0;
1630b57cec5SDimitry Andric   auto I = StringTable.find(S);
1640b57cec5SDimitry Andric   assert(I != StringTable.end());
1650b57cec5SDimitry Andric   return I->second;
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric void CodeViewContext::emitStringTable(MCObjectStreamer &OS) {
1690b57cec5SDimitry Andric   MCContext &Ctx = OS.getContext();
1700b57cec5SDimitry Andric   MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin", false),
1710b57cec5SDimitry Andric            *StringEnd = Ctx.createTempSymbol("strtab_end", false);
1720b57cec5SDimitry Andric 
1735ffd83dbSDimitry Andric   OS.emitInt32(uint32_t(DebugSubsectionKind::StringTable));
1740b57cec5SDimitry Andric   OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4);
1755ffd83dbSDimitry Andric   OS.emitLabel(StringBegin);
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   // Put the string table data fragment here, if we haven't already put it
1780b57cec5SDimitry Andric   // somewhere else. If somebody wants two string tables in their .s file, one
1790b57cec5SDimitry Andric   // will just be empty.
1800b57cec5SDimitry Andric   if (!InsertedStrTabFragment) {
1810b57cec5SDimitry Andric     OS.insert(getStringTableFragment());
1820b57cec5SDimitry Andric     InsertedStrTabFragment = true;
1830b57cec5SDimitry Andric   }
1840b57cec5SDimitry Andric 
185bdd1243dSDimitry Andric   OS.emitValueToAlignment(Align(4), 0);
1860b57cec5SDimitry Andric 
1875ffd83dbSDimitry Andric   OS.emitLabel(StringEnd);
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) {
1910b57cec5SDimitry Andric   // Do nothing if there are no file checksums. Microsoft's linker rejects empty
1920b57cec5SDimitry Andric   // CodeView substreams.
1930b57cec5SDimitry Andric   if (Files.empty())
1940b57cec5SDimitry Andric     return;
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   MCContext &Ctx = OS.getContext();
1970b57cec5SDimitry Andric   MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin", false),
1980b57cec5SDimitry Andric            *FileEnd = Ctx.createTempSymbol("filechecksums_end", false);
1990b57cec5SDimitry Andric 
2005ffd83dbSDimitry Andric   OS.emitInt32(uint32_t(DebugSubsectionKind::FileChecksums));
2010b57cec5SDimitry Andric   OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4);
2025ffd83dbSDimitry Andric   OS.emitLabel(FileBegin);
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   unsigned CurrentOffset = 0;
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric   // Emit an array of FileChecksum entries. We index into this table using the
2070b57cec5SDimitry Andric   // user-provided file number.  Each entry may be a variable number of bytes
2080b57cec5SDimitry Andric   // determined by the checksum kind and size.
2090b57cec5SDimitry Andric   for (auto File : Files) {
2105ffd83dbSDimitry Andric     OS.emitAssignment(File.ChecksumTableOffset,
2110b57cec5SDimitry Andric                       MCConstantExpr::create(CurrentOffset, Ctx));
2120b57cec5SDimitry Andric     CurrentOffset += 4; // String table offset.
2130b57cec5SDimitry Andric     if (!File.ChecksumKind) {
2140b57cec5SDimitry Andric       CurrentOffset +=
2150b57cec5SDimitry Andric           4; // One byte each for checksum size and kind, then align to 4 bytes.
2160b57cec5SDimitry Andric     } else {
2170b57cec5SDimitry Andric       CurrentOffset += 2; // One byte each for checksum size and kind.
2180b57cec5SDimitry Andric       CurrentOffset += File.Checksum.size();
2190b57cec5SDimitry Andric       CurrentOffset = alignTo(CurrentOffset, 4);
2200b57cec5SDimitry Andric     }
2210b57cec5SDimitry Andric 
2225ffd83dbSDimitry Andric     OS.emitInt32(File.StringTableOffset);
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric     if (!File.ChecksumKind) {
2250b57cec5SDimitry Andric       // There is no checksum.  Therefore zero the next two fields and align
2260b57cec5SDimitry Andric       // back to 4 bytes.
2275ffd83dbSDimitry Andric       OS.emitInt32(0);
2280b57cec5SDimitry Andric       continue;
2290b57cec5SDimitry Andric     }
2305ffd83dbSDimitry Andric     OS.emitInt8(static_cast<uint8_t>(File.Checksum.size()));
2315ffd83dbSDimitry Andric     OS.emitInt8(File.ChecksumKind);
2325ffd83dbSDimitry Andric     OS.emitBytes(toStringRef(File.Checksum));
233bdd1243dSDimitry Andric     OS.emitValueToAlignment(Align(4));
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric 
2365ffd83dbSDimitry Andric   OS.emitLabel(FileEnd);
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   ChecksumOffsetsAssigned = true;
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric // Output checksum table offset of the given file number.  It is possible that
2420b57cec5SDimitry Andric // not all files have been registered yet, and so the offset cannot be
2430b57cec5SDimitry Andric // calculated.  In this case a symbol representing the offset is emitted, and
2440b57cec5SDimitry Andric // the value of this symbol will be fixed up at a later time.
2450b57cec5SDimitry Andric void CodeViewContext::emitFileChecksumOffset(MCObjectStreamer &OS,
2460b57cec5SDimitry Andric                                              unsigned FileNo) {
2470b57cec5SDimitry Andric   unsigned Idx = FileNo - 1;
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric   if (Idx >= Files.size())
2500b57cec5SDimitry Andric     Files.resize(Idx + 1);
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric   if (ChecksumOffsetsAssigned) {
2535ffd83dbSDimitry Andric     OS.emitSymbolValue(Files[Idx].ChecksumTableOffset, 4);
2540b57cec5SDimitry Andric     return;
2550b57cec5SDimitry Andric   }
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric   const MCSymbolRefExpr *SRE =
2580b57cec5SDimitry Andric       MCSymbolRefExpr::create(Files[Idx].ChecksumTableOffset, OS.getContext());
2590b57cec5SDimitry Andric 
2605ffd83dbSDimitry Andric   OS.emitValueImpl(SRE, 4);
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric void CodeViewContext::addLineEntry(const MCCVLoc &LineEntry) {
2640b57cec5SDimitry Andric   size_t Offset = MCCVLines.size();
2650b57cec5SDimitry Andric   auto I = MCCVLineStartStop.insert(
2660b57cec5SDimitry Andric       {LineEntry.getFunctionId(), {Offset, Offset + 1}});
2670b57cec5SDimitry Andric   if (!I.second)
2680b57cec5SDimitry Andric     I.first->second.second = Offset + 1;
2690b57cec5SDimitry Andric   MCCVLines.push_back(LineEntry);
2700b57cec5SDimitry Andric }
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric std::vector<MCCVLoc>
2730b57cec5SDimitry Andric CodeViewContext::getFunctionLineEntries(unsigned FuncId) {
2740b57cec5SDimitry Andric   std::vector<MCCVLoc> FilteredLines;
2755f757f3fSDimitry Andric   size_t LocBegin;
2765f757f3fSDimitry Andric   size_t LocEnd;
2775f757f3fSDimitry Andric   std::tie(LocBegin, LocEnd) = getLineExtentIncludingInlinees(FuncId);
2785f757f3fSDimitry Andric   if (LocBegin >= LocEnd) {
2795f757f3fSDimitry Andric     return FilteredLines;
2805f757f3fSDimitry Andric   }
2815f757f3fSDimitry Andric 
2820b57cec5SDimitry Andric   MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(FuncId);
2835f757f3fSDimitry Andric   for (size_t Idx = LocBegin; Idx != LocEnd; ++Idx) {
2840b57cec5SDimitry Andric     unsigned LocationFuncId = MCCVLines[Idx].getFunctionId();
2850b57cec5SDimitry Andric     if (LocationFuncId == FuncId) {
2860b57cec5SDimitry Andric       // This was a .cv_loc directly for FuncId, so record it.
2870b57cec5SDimitry Andric       FilteredLines.push_back(MCCVLines[Idx]);
2880b57cec5SDimitry Andric     } else {
2890b57cec5SDimitry Andric       // Check if the current location is inlined in this function. If it is,
2900b57cec5SDimitry Andric       // synthesize a statement .cv_loc at the original inlined call site.
2910b57cec5SDimitry Andric       auto I = SiteInfo->InlinedAtMap.find(LocationFuncId);
2920b57cec5SDimitry Andric       if (I != SiteInfo->InlinedAtMap.end()) {
2930b57cec5SDimitry Andric         MCCVFunctionInfo::LineInfo &IA = I->second;
2940b57cec5SDimitry Andric         // Only add the location if it differs from the previous location.
2950b57cec5SDimitry Andric         // Large inlined calls will have many .cv_loc entries and we only need
2960b57cec5SDimitry Andric         // one line table entry in the parent function.
2970b57cec5SDimitry Andric         if (FilteredLines.empty() ||
2980b57cec5SDimitry Andric             FilteredLines.back().getFileNum() != IA.File ||
2990b57cec5SDimitry Andric             FilteredLines.back().getLine() != IA.Line ||
3000b57cec5SDimitry Andric             FilteredLines.back().getColumn() != IA.Col) {
3015f757f3fSDimitry Andric           FilteredLines.push_back(MCCVLoc(MCCVLines[Idx].getLabel(), FuncId,
3025f757f3fSDimitry Andric                                           IA.File, IA.Line, IA.Col, false,
3035f757f3fSDimitry Andric                                           false));
3040b57cec5SDimitry Andric         }
3050b57cec5SDimitry Andric       }
3060b57cec5SDimitry Andric     }
3070b57cec5SDimitry Andric   }
3080b57cec5SDimitry Andric   return FilteredLines;
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric 
3110b57cec5SDimitry Andric std::pair<size_t, size_t> CodeViewContext::getLineExtent(unsigned FuncId) {
3120b57cec5SDimitry Andric   auto I = MCCVLineStartStop.find(FuncId);
3130b57cec5SDimitry Andric   // Return an empty extent if there are no cv_locs for this function id.
3140b57cec5SDimitry Andric   if (I == MCCVLineStartStop.end())
3150b57cec5SDimitry Andric     return {~0ULL, 0};
3160b57cec5SDimitry Andric   return I->second;
3170b57cec5SDimitry Andric }
3180b57cec5SDimitry Andric 
3195f757f3fSDimitry Andric std::pair<size_t, size_t>
3205f757f3fSDimitry Andric CodeViewContext::getLineExtentIncludingInlinees(unsigned FuncId) {
3215f757f3fSDimitry Andric   size_t LocBegin;
3225f757f3fSDimitry Andric   size_t LocEnd;
3235f757f3fSDimitry Andric   std::tie(LocBegin, LocEnd) = getLineExtent(FuncId);
3245f757f3fSDimitry Andric 
3255f757f3fSDimitry Andric   // Include all child inline call sites in our extent.
3265f757f3fSDimitry Andric   MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(FuncId);
3275f757f3fSDimitry Andric   if (SiteInfo) {
3285f757f3fSDimitry Andric     for (auto &KV : SiteInfo->InlinedAtMap) {
3295f757f3fSDimitry Andric       unsigned ChildId = KV.first;
3305f757f3fSDimitry Andric       auto Extent = getLineExtent(ChildId);
3315f757f3fSDimitry Andric       LocBegin = std::min(LocBegin, Extent.first);
3325f757f3fSDimitry Andric       LocEnd = std::max(LocEnd, Extent.second);
3335f757f3fSDimitry Andric     }
3345f757f3fSDimitry Andric   }
3355f757f3fSDimitry Andric 
3365f757f3fSDimitry Andric   return {LocBegin, LocEnd};
3375f757f3fSDimitry Andric }
3385f757f3fSDimitry Andric 
3390b57cec5SDimitry Andric ArrayRef<MCCVLoc> CodeViewContext::getLinesForExtent(size_t L, size_t R) {
3400b57cec5SDimitry Andric   if (R <= L)
341bdd1243dSDimitry Andric     return std::nullopt;
3420b57cec5SDimitry Andric   if (L >= MCCVLines.size())
343bdd1243dSDimitry Andric     return std::nullopt;
344bdd1243dSDimitry Andric   return ArrayRef(&MCCVLines[L], R - L);
3450b57cec5SDimitry Andric }
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS,
3480b57cec5SDimitry Andric                                                unsigned FuncId,
3490b57cec5SDimitry Andric                                                const MCSymbol *FuncBegin,
3500b57cec5SDimitry Andric                                                const MCSymbol *FuncEnd) {
3510b57cec5SDimitry Andric   MCContext &Ctx = OS.getContext();
3520b57cec5SDimitry Andric   MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin", false),
3530b57cec5SDimitry Andric            *LineEnd = Ctx.createTempSymbol("linetable_end", false);
3540b57cec5SDimitry Andric 
3555ffd83dbSDimitry Andric   OS.emitInt32(uint32_t(DebugSubsectionKind::Lines));
3560b57cec5SDimitry Andric   OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4);
3575ffd83dbSDimitry Andric   OS.emitLabel(LineBegin);
35881ad6265SDimitry Andric   OS.emitCOFFSecRel32(FuncBegin, /*Offset=*/0);
35981ad6265SDimitry Andric   OS.emitCOFFSectionIndex(FuncBegin);
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric   // Actual line info.
3620b57cec5SDimitry Andric   std::vector<MCCVLoc> Locs = getFunctionLineEntries(FuncId);
3630b57cec5SDimitry Andric   bool HaveColumns = any_of(Locs, [](const MCCVLoc &LineEntry) {
3640b57cec5SDimitry Andric     return LineEntry.getColumn() != 0;
3650b57cec5SDimitry Andric   });
3665ffd83dbSDimitry Andric   OS.emitInt16(HaveColumns ? int(LF_HaveColumns) : 0);
3670b57cec5SDimitry Andric   OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4);
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   for (auto I = Locs.begin(), E = Locs.end(); I != E;) {
3700b57cec5SDimitry Andric     // Emit a file segment for the run of locations that share a file id.
3710b57cec5SDimitry Andric     unsigned CurFileNum = I->getFileNum();
3720b57cec5SDimitry Andric     auto FileSegEnd =
3730b57cec5SDimitry Andric         std::find_if(I, E, [CurFileNum](const MCCVLoc &Loc) {
3740b57cec5SDimitry Andric           return Loc.getFileNum() != CurFileNum;
3750b57cec5SDimitry Andric         });
3760b57cec5SDimitry Andric     unsigned EntryCount = FileSegEnd - I;
3770b57cec5SDimitry Andric     OS.AddComment(
3780b57cec5SDimitry Andric         "Segment for file '" +
3790b57cec5SDimitry Andric         Twine(getStringTableFragment()
3800b57cec5SDimitry Andric                   ->getContents()[Files[CurFileNum - 1].StringTableOffset]) +
3810b57cec5SDimitry Andric         "' begins");
3825ffd83dbSDimitry Andric     OS.emitCVFileChecksumOffsetDirective(CurFileNum);
3835ffd83dbSDimitry Andric     OS.emitInt32(EntryCount);
3840b57cec5SDimitry Andric     uint32_t SegmentSize = 12;
3850b57cec5SDimitry Andric     SegmentSize += 8 * EntryCount;
3860b57cec5SDimitry Andric     if (HaveColumns)
3870b57cec5SDimitry Andric       SegmentSize += 4 * EntryCount;
3885ffd83dbSDimitry Andric     OS.emitInt32(SegmentSize);
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric     for (auto J = I; J != FileSegEnd; ++J) {
3910b57cec5SDimitry Andric       OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4);
3920b57cec5SDimitry Andric       unsigned LineData = J->getLine();
3930b57cec5SDimitry Andric       if (J->isStmt())
3940b57cec5SDimitry Andric         LineData |= LineInfo::StatementFlag;
3955ffd83dbSDimitry Andric       OS.emitInt32(LineData);
3960b57cec5SDimitry Andric     }
3970b57cec5SDimitry Andric     if (HaveColumns) {
3980b57cec5SDimitry Andric       for (auto J = I; J != FileSegEnd; ++J) {
3995ffd83dbSDimitry Andric         OS.emitInt16(J->getColumn());
4005ffd83dbSDimitry Andric         OS.emitInt16(0);
4010b57cec5SDimitry Andric       }
4020b57cec5SDimitry Andric     }
4030b57cec5SDimitry Andric     I = FileSegEnd;
4040b57cec5SDimitry Andric   }
4055ffd83dbSDimitry Andric   OS.emitLabel(LineEnd);
4060b57cec5SDimitry Andric }
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric static bool compressAnnotation(uint32_t Data, SmallVectorImpl<char> &Buffer) {
4090b57cec5SDimitry Andric   if (isUInt<7>(Data)) {
4100b57cec5SDimitry Andric     Buffer.push_back(Data);
4110b57cec5SDimitry Andric     return true;
4120b57cec5SDimitry Andric   }
4130b57cec5SDimitry Andric 
4140b57cec5SDimitry Andric   if (isUInt<14>(Data)) {
4150b57cec5SDimitry Andric     Buffer.push_back((Data >> 8) | 0x80);
4160b57cec5SDimitry Andric     Buffer.push_back(Data & 0xff);
4170b57cec5SDimitry Andric     return true;
4180b57cec5SDimitry Andric   }
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric   if (isUInt<29>(Data)) {
4210b57cec5SDimitry Andric     Buffer.push_back((Data >> 24) | 0xC0);
4220b57cec5SDimitry Andric     Buffer.push_back((Data >> 16) & 0xff);
4230b57cec5SDimitry Andric     Buffer.push_back((Data >> 8) & 0xff);
4240b57cec5SDimitry Andric     Buffer.push_back(Data & 0xff);
4250b57cec5SDimitry Andric     return true;
4260b57cec5SDimitry Andric   }
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric   return false;
4290b57cec5SDimitry Andric }
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric static bool compressAnnotation(BinaryAnnotationsOpCode Annotation,
4320b57cec5SDimitry Andric                                SmallVectorImpl<char> &Buffer) {
4330b57cec5SDimitry Andric   return compressAnnotation(static_cast<uint32_t>(Annotation), Buffer);
4340b57cec5SDimitry Andric }
4350b57cec5SDimitry Andric 
4360b57cec5SDimitry Andric static uint32_t encodeSignedNumber(uint32_t Data) {
4370b57cec5SDimitry Andric   if (Data >> 31)
4380b57cec5SDimitry Andric     return ((-Data) << 1) | 1;
4390b57cec5SDimitry Andric   return Data << 1;
4400b57cec5SDimitry Andric }
4410b57cec5SDimitry Andric 
4420b57cec5SDimitry Andric void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS,
4430b57cec5SDimitry Andric                                                      unsigned PrimaryFunctionId,
4440b57cec5SDimitry Andric                                                      unsigned SourceFileId,
4450b57cec5SDimitry Andric                                                      unsigned SourceLineNum,
4460b57cec5SDimitry Andric                                                      const MCSymbol *FnStartSym,
4470b57cec5SDimitry Andric                                                      const MCSymbol *FnEndSym) {
4480b57cec5SDimitry Andric   // Create and insert a fragment into the current section that will be encoded
4490b57cec5SDimitry Andric   // later.
450*0fca6ea1SDimitry Andric   auto *F = MCCtx->allocFragment<MCCVInlineLineTableFragment>(
451*0fca6ea1SDimitry Andric       PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
452*0fca6ea1SDimitry Andric   OS.insert(F);
4530b57cec5SDimitry Andric }
4540b57cec5SDimitry Andric 
4550b57cec5SDimitry Andric MCFragment *CodeViewContext::emitDefRange(
4560b57cec5SDimitry Andric     MCObjectStreamer &OS,
4570b57cec5SDimitry Andric     ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
4580b57cec5SDimitry Andric     StringRef FixedSizePortion) {
4590b57cec5SDimitry Andric   // Create and insert a fragment into the current section that will be encoded
4600b57cec5SDimitry Andric   // later.
461*0fca6ea1SDimitry Andric   auto *F =
462*0fca6ea1SDimitry Andric       MCCtx->allocFragment<MCCVDefRangeFragment>(Ranges, FixedSizePortion);
463*0fca6ea1SDimitry Andric   OS.insert(F);
464*0fca6ea1SDimitry Andric   return F;
4650b57cec5SDimitry Andric }
4660b57cec5SDimitry Andric 
467*0fca6ea1SDimitry Andric static unsigned computeLabelDiff(const MCAssembler &Asm, const MCSymbol *Begin,
4680b57cec5SDimitry Andric                                  const MCSymbol *End) {
469*0fca6ea1SDimitry Andric   MCContext &Ctx = Asm.getContext();
4700b57cec5SDimitry Andric   MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
4710b57cec5SDimitry Andric   const MCExpr *BeginRef = MCSymbolRefExpr::create(Begin, Variant, Ctx),
4720b57cec5SDimitry Andric                *EndRef = MCSymbolRefExpr::create(End, Variant, Ctx);
4730b57cec5SDimitry Andric   const MCExpr *AddrDelta =
4740b57cec5SDimitry Andric       MCBinaryExpr::create(MCBinaryExpr::Sub, EndRef, BeginRef, Ctx);
4750b57cec5SDimitry Andric   int64_t Result;
476*0fca6ea1SDimitry Andric   bool Success = AddrDelta->evaluateKnownAbsolute(Result, Asm);
4770b57cec5SDimitry Andric   assert(Success && "failed to evaluate label difference as absolute");
4780b57cec5SDimitry Andric   (void)Success;
4790b57cec5SDimitry Andric   assert(Result >= 0 && "negative label difference requested");
4800b57cec5SDimitry Andric   assert(Result < UINT_MAX && "label difference greater than 2GB");
4810b57cec5SDimitry Andric   return unsigned(Result);
4820b57cec5SDimitry Andric }
4830b57cec5SDimitry Andric 
484*0fca6ea1SDimitry Andric void CodeViewContext::encodeInlineLineTable(const MCAssembler &Asm,
4850b57cec5SDimitry Andric                                             MCCVInlineLineTableFragment &Frag) {
4860b57cec5SDimitry Andric   size_t LocBegin;
4870b57cec5SDimitry Andric   size_t LocEnd;
4885f757f3fSDimitry Andric   std::tie(LocBegin, LocEnd) = getLineExtentIncludingInlinees(Frag.SiteFuncId);
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric   if (LocBegin >= LocEnd)
4910b57cec5SDimitry Andric     return;
4920b57cec5SDimitry Andric   ArrayRef<MCCVLoc> Locs = getLinesForExtent(LocBegin, LocEnd);
4930b57cec5SDimitry Andric   if (Locs.empty())
4940b57cec5SDimitry Andric     return;
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric   // Check that the locations are all in the same section.
4970b57cec5SDimitry Andric #ifndef NDEBUG
4980b57cec5SDimitry Andric   const MCSection *FirstSec = &Locs.front().getLabel()->getSection();
4990b57cec5SDimitry Andric   for (const MCCVLoc &Loc : Locs) {
5000b57cec5SDimitry Andric     if (&Loc.getLabel()->getSection() != FirstSec) {
5010b57cec5SDimitry Andric       errs() << ".cv_loc " << Loc.getFunctionId() << ' ' << Loc.getFileNum()
5020b57cec5SDimitry Andric              << ' ' << Loc.getLine() << ' ' << Loc.getColumn()
5030b57cec5SDimitry Andric              << " is in the wrong section\n";
5040b57cec5SDimitry Andric       llvm_unreachable(".cv_loc crosses sections");
5050b57cec5SDimitry Andric     }
5060b57cec5SDimitry Andric   }
5070b57cec5SDimitry Andric #endif
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric   // Make an artificial start location using the function start and the inlinee
5100b57cec5SDimitry Andric   // lines start location information. All deltas start relative to this
5110b57cec5SDimitry Andric   // location.
5120b57cec5SDimitry Andric   MCCVLoc StartLoc = Locs.front();
5130b57cec5SDimitry Andric   StartLoc.setLabel(Frag.getFnStartSym());
5140b57cec5SDimitry Andric   StartLoc.setFileNum(Frag.StartFileId);
5150b57cec5SDimitry Andric   StartLoc.setLine(Frag.StartLineNum);
5160b57cec5SDimitry Andric   bool HaveOpenRange = false;
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric   const MCSymbol *LastLabel = Frag.getFnStartSym();
5190b57cec5SDimitry Andric   MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc;
5200b57cec5SDimitry Andric   LastSourceLoc.File = Frag.StartFileId;
5210b57cec5SDimitry Andric   LastSourceLoc.Line = Frag.StartLineNum;
5220b57cec5SDimitry Andric 
5235f757f3fSDimitry Andric   MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId);
5245f757f3fSDimitry Andric 
5250b57cec5SDimitry Andric   SmallVectorImpl<char> &Buffer = Frag.getContents();
5260b57cec5SDimitry Andric   Buffer.clear(); // Clear old contents if we went through relaxation.
5270b57cec5SDimitry Andric   for (const MCCVLoc &Loc : Locs) {
5280b57cec5SDimitry Andric     // Exit early if our line table would produce an oversized InlineSiteSym
5290b57cec5SDimitry Andric     // record. Account for the ChangeCodeLength annotation emitted after the
5300b57cec5SDimitry Andric     // loop ends.
5310b57cec5SDimitry Andric     constexpr uint32_t InlineSiteSize = 12;
5320b57cec5SDimitry Andric     constexpr uint32_t AnnotationSize = 8;
5330b57cec5SDimitry Andric     size_t MaxBufferSize = MaxRecordLength - InlineSiteSize - AnnotationSize;
5340b57cec5SDimitry Andric     if (Buffer.size() >= MaxBufferSize)
5350b57cec5SDimitry Andric       break;
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric     if (Loc.getFunctionId() == Frag.SiteFuncId) {
5380b57cec5SDimitry Andric       CurSourceLoc.File = Loc.getFileNum();
5390b57cec5SDimitry Andric       CurSourceLoc.Line = Loc.getLine();
5400b57cec5SDimitry Andric     } else {
5410b57cec5SDimitry Andric       auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId());
5420b57cec5SDimitry Andric       if (I != SiteInfo->InlinedAtMap.end()) {
5430b57cec5SDimitry Andric         // This .cv_loc is from a child inline call site. Use the source
5440b57cec5SDimitry Andric         // location of the inlined call site instead of the .cv_loc directive
5450b57cec5SDimitry Andric         // source location.
5460b57cec5SDimitry Andric         CurSourceLoc = I->second;
5470b57cec5SDimitry Andric       } else {
5480b57cec5SDimitry Andric         // We've hit a cv_loc not attributed to this inline call site. Use this
5490b57cec5SDimitry Andric         // label to end the PC range.
5500b57cec5SDimitry Andric         if (HaveOpenRange) {
551*0fca6ea1SDimitry Andric           unsigned Length = computeLabelDiff(Asm, LastLabel, Loc.getLabel());
5520b57cec5SDimitry Andric           compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
5530b57cec5SDimitry Andric           compressAnnotation(Length, Buffer);
5540b57cec5SDimitry Andric           LastLabel = Loc.getLabel();
5550b57cec5SDimitry Andric         }
5560b57cec5SDimitry Andric         HaveOpenRange = false;
5570b57cec5SDimitry Andric         continue;
5580b57cec5SDimitry Andric       }
5590b57cec5SDimitry Andric     }
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric     // Skip this .cv_loc if we have an open range and this isn't a meaningful
5620b57cec5SDimitry Andric     // source location update. The current table format does not support column
5630b57cec5SDimitry Andric     // info, so we can skip updates for those.
5640b57cec5SDimitry Andric     if (HaveOpenRange && CurSourceLoc.File == LastSourceLoc.File &&
5650b57cec5SDimitry Andric         CurSourceLoc.Line == LastSourceLoc.Line)
5660b57cec5SDimitry Andric       continue;
5670b57cec5SDimitry Andric 
5680b57cec5SDimitry Andric     HaveOpenRange = true;
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric     if (CurSourceLoc.File != LastSourceLoc.File) {
5710b57cec5SDimitry Andric       unsigned FileOffset = static_cast<const MCConstantExpr *>(
5720b57cec5SDimitry Andric                                 Files[CurSourceLoc.File - 1]
5730b57cec5SDimitry Andric                                     .ChecksumTableOffset->getVariableValue())
5740b57cec5SDimitry Andric                                 ->getValue();
5750b57cec5SDimitry Andric       compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer);
5760b57cec5SDimitry Andric       compressAnnotation(FileOffset, Buffer);
5770b57cec5SDimitry Andric     }
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric     int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line;
5800b57cec5SDimitry Andric     unsigned EncodedLineDelta = encodeSignedNumber(LineDelta);
581*0fca6ea1SDimitry Andric     unsigned CodeDelta = computeLabelDiff(Asm, LastLabel, Loc.getLabel());
582e8d8bef9SDimitry Andric     if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) {
5830b57cec5SDimitry Andric       // The ChangeCodeOffsetAndLineOffset combination opcode is used when the
5840b57cec5SDimitry Andric       // encoded line delta uses 3 or fewer set bits and the code offset fits
5850b57cec5SDimitry Andric       // in one nibble.
5860b57cec5SDimitry Andric       unsigned Operand = (EncodedLineDelta << 4) | CodeDelta;
5870b57cec5SDimitry Andric       compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset,
5880b57cec5SDimitry Andric                          Buffer);
5890b57cec5SDimitry Andric       compressAnnotation(Operand, Buffer);
5900b57cec5SDimitry Andric     } else {
5910b57cec5SDimitry Andric       // Otherwise use the separate line and code deltas.
5920b57cec5SDimitry Andric       if (LineDelta != 0) {
5930b57cec5SDimitry Andric         compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
5940b57cec5SDimitry Andric         compressAnnotation(EncodedLineDelta, Buffer);
5950b57cec5SDimitry Andric       }
5960b57cec5SDimitry Andric       compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffset, Buffer);
5970b57cec5SDimitry Andric       compressAnnotation(CodeDelta, Buffer);
5980b57cec5SDimitry Andric     }
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric     LastLabel = Loc.getLabel();
6010b57cec5SDimitry Andric     LastSourceLoc = CurSourceLoc;
6020b57cec5SDimitry Andric   }
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric   assert(HaveOpenRange);
6050b57cec5SDimitry Andric 
6060b57cec5SDimitry Andric   unsigned EndSymLength =
607*0fca6ea1SDimitry Andric       computeLabelDiff(Asm, LastLabel, Frag.getFnEndSym());
6080b57cec5SDimitry Andric   unsigned LocAfterLength = ~0U;
6090b57cec5SDimitry Andric   ArrayRef<MCCVLoc> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1);
6100b57cec5SDimitry Andric   if (!LocAfter.empty()) {
6110b57cec5SDimitry Andric     // Only try to compute this difference if we're in the same section.
6120b57cec5SDimitry Andric     const MCCVLoc &Loc = LocAfter[0];
6130b57cec5SDimitry Andric     if (&Loc.getLabel()->getSection() == &LastLabel->getSection())
614*0fca6ea1SDimitry Andric       LocAfterLength = computeLabelDiff(Asm, LastLabel, Loc.getLabel());
6150b57cec5SDimitry Andric   }
6160b57cec5SDimitry Andric 
6170b57cec5SDimitry Andric   compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
6180b57cec5SDimitry Andric   compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer);
6190b57cec5SDimitry Andric }
6200b57cec5SDimitry Andric 
621*0fca6ea1SDimitry Andric void CodeViewContext::encodeDefRange(const MCAssembler &Asm,
6220b57cec5SDimitry Andric                                      MCCVDefRangeFragment &Frag) {
623*0fca6ea1SDimitry Andric   MCContext &Ctx = Asm.getContext();
6240b57cec5SDimitry Andric   SmallVectorImpl<char> &Contents = Frag.getContents();
6250b57cec5SDimitry Andric   Contents.clear();
6260b57cec5SDimitry Andric   SmallVectorImpl<MCFixup> &Fixups = Frag.getFixups();
6270b57cec5SDimitry Andric   Fixups.clear();
6280b57cec5SDimitry Andric   raw_svector_ostream OS(Contents);
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric   // Compute all the sizes up front.
6310b57cec5SDimitry Andric   SmallVector<std::pair<unsigned, unsigned>, 4> GapAndRangeSizes;
6320b57cec5SDimitry Andric   const MCSymbol *LastLabel = nullptr;
6330b57cec5SDimitry Andric   for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) {
6340b57cec5SDimitry Andric     unsigned GapSize =
635*0fca6ea1SDimitry Andric         LastLabel ? computeLabelDiff(Asm, LastLabel, Range.first) : 0;
636*0fca6ea1SDimitry Andric     unsigned RangeSize = computeLabelDiff(Asm, Range.first, Range.second);
6370b57cec5SDimitry Andric     GapAndRangeSizes.push_back({GapSize, RangeSize});
6380b57cec5SDimitry Andric     LastLabel = Range.second;
6390b57cec5SDimitry Andric   }
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric   // Write down each range where the variable is defined.
6420b57cec5SDimitry Andric   for (size_t I = 0, E = Frag.getRanges().size(); I != E;) {
6430b57cec5SDimitry Andric     // If the range size of multiple consecutive ranges is under the max,
6440b57cec5SDimitry Andric     // combine the ranges and emit some gaps.
6450b57cec5SDimitry Andric     const MCSymbol *RangeBegin = Frag.getRanges()[I].first;
6460b57cec5SDimitry Andric     unsigned RangeSize = GapAndRangeSizes[I].second;
6470b57cec5SDimitry Andric     size_t J = I + 1;
6480b57cec5SDimitry Andric     for (; J != E; ++J) {
6490b57cec5SDimitry Andric       unsigned GapAndRangeSize = GapAndRangeSizes[J].first + GapAndRangeSizes[J].second;
6500b57cec5SDimitry Andric       if (RangeSize + GapAndRangeSize > MaxDefRange)
6510b57cec5SDimitry Andric         break;
6520b57cec5SDimitry Andric       RangeSize += GapAndRangeSize;
6530b57cec5SDimitry Andric     }
6540b57cec5SDimitry Andric     unsigned NumGaps = J - I - 1;
6550b57cec5SDimitry Andric 
6565f757f3fSDimitry Andric     support::endian::Writer LEWriter(OS, llvm::endianness::little);
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric     unsigned Bias = 0;
6590b57cec5SDimitry Andric     // We must split the range into chunks of MaxDefRange, this is a fundamental
6600b57cec5SDimitry Andric     // limitation of the file format.
6610b57cec5SDimitry Andric     do {
6620b57cec5SDimitry Andric       uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize);
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric       const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(RangeBegin, Ctx);
6650b57cec5SDimitry Andric       const MCBinaryExpr *BE =
6660b57cec5SDimitry Andric           MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx);
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric       // Each record begins with a 2-byte number indicating how large the record
6690b57cec5SDimitry Andric       // is.
6700b57cec5SDimitry Andric       StringRef FixedSizePortion = Frag.getFixedSizePortion();
6710b57cec5SDimitry Andric       // Our record is a fixed sized prefix and a LocalVariableAddrRange that we
6720b57cec5SDimitry Andric       // are artificially constructing.
6730b57cec5SDimitry Andric       size_t RecordSize = FixedSizePortion.size() +
6740b57cec5SDimitry Andric                           sizeof(LocalVariableAddrRange) + 4 * NumGaps;
6750b57cec5SDimitry Andric       // Write out the record size.
6760b57cec5SDimitry Andric       LEWriter.write<uint16_t>(RecordSize);
6770b57cec5SDimitry Andric       // Write out the fixed size prefix.
6780b57cec5SDimitry Andric       OS << FixedSizePortion;
6790b57cec5SDimitry Andric       // Make space for a fixup that will eventually have a section relative
6800b57cec5SDimitry Andric       // relocation pointing at the offset where the variable becomes live.
6810b57cec5SDimitry Andric       Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4));
6820b57cec5SDimitry Andric       LEWriter.write<uint32_t>(0); // Fixup for code start.
6830b57cec5SDimitry Andric       // Make space for a fixup that will record the section index for the code.
6840b57cec5SDimitry Andric       Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2));
6850b57cec5SDimitry Andric       LEWriter.write<uint16_t>(0); // Fixup for section index.
6860b57cec5SDimitry Andric       // Write down the range's extent.
6870b57cec5SDimitry Andric       LEWriter.write<uint16_t>(Chunk);
6880b57cec5SDimitry Andric 
6890b57cec5SDimitry Andric       // Move on to the next range.
6900b57cec5SDimitry Andric       Bias += Chunk;
6910b57cec5SDimitry Andric       RangeSize -= Chunk;
6920b57cec5SDimitry Andric     } while (RangeSize > 0);
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric     // Emit the gaps afterwards.
6950b57cec5SDimitry Andric     assert((NumGaps == 0 || Bias <= MaxDefRange) &&
6960b57cec5SDimitry Andric            "large ranges should not have gaps");
6970b57cec5SDimitry Andric     unsigned GapStartOffset = GapAndRangeSizes[I].second;
6980b57cec5SDimitry Andric     for (++I; I != J; ++I) {
6990b57cec5SDimitry Andric       unsigned GapSize, RangeSize;
7000b57cec5SDimitry Andric       assert(I < GapAndRangeSizes.size());
7010b57cec5SDimitry Andric       std::tie(GapSize, RangeSize) = GapAndRangeSizes[I];
7020b57cec5SDimitry Andric       LEWriter.write<uint16_t>(GapStartOffset);
7030b57cec5SDimitry Andric       LEWriter.write<uint16_t>(GapSize);
7040b57cec5SDimitry Andric       GapStartOffset += GapSize + RangeSize;
7050b57cec5SDimitry Andric     }
7060b57cec5SDimitry Andric   }
7070b57cec5SDimitry Andric }
708