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