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