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