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 188bdd1243dSDimitry 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)); 236bdd1243dSDimitry 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; 278*5f757f3fSDimitry Andric size_t LocBegin; 279*5f757f3fSDimitry Andric size_t LocEnd; 280*5f757f3fSDimitry Andric std::tie(LocBegin, LocEnd) = getLineExtentIncludingInlinees(FuncId); 281*5f757f3fSDimitry Andric if (LocBegin >= LocEnd) { 282*5f757f3fSDimitry Andric return FilteredLines; 283*5f757f3fSDimitry Andric } 284*5f757f3fSDimitry Andric 2850b57cec5SDimitry Andric MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(FuncId); 286*5f757f3fSDimitry Andric for (size_t Idx = LocBegin; Idx != LocEnd; ++Idx) { 2870b57cec5SDimitry Andric unsigned LocationFuncId = MCCVLines[Idx].getFunctionId(); 2880b57cec5SDimitry Andric if (LocationFuncId == FuncId) { 2890b57cec5SDimitry Andric // This was a .cv_loc directly for FuncId, so record it. 2900b57cec5SDimitry Andric FilteredLines.push_back(MCCVLines[Idx]); 2910b57cec5SDimitry Andric } else { 2920b57cec5SDimitry Andric // Check if the current location is inlined in this function. If it is, 2930b57cec5SDimitry Andric // synthesize a statement .cv_loc at the original inlined call site. 2940b57cec5SDimitry Andric auto I = SiteInfo->InlinedAtMap.find(LocationFuncId); 2950b57cec5SDimitry Andric if (I != SiteInfo->InlinedAtMap.end()) { 2960b57cec5SDimitry Andric MCCVFunctionInfo::LineInfo &IA = I->second; 2970b57cec5SDimitry Andric // Only add the location if it differs from the previous location. 2980b57cec5SDimitry Andric // Large inlined calls will have many .cv_loc entries and we only need 2990b57cec5SDimitry Andric // one line table entry in the parent function. 3000b57cec5SDimitry Andric if (FilteredLines.empty() || 3010b57cec5SDimitry Andric FilteredLines.back().getFileNum() != IA.File || 3020b57cec5SDimitry Andric FilteredLines.back().getLine() != IA.Line || 3030b57cec5SDimitry Andric FilteredLines.back().getColumn() != IA.Col) { 304*5f757f3fSDimitry Andric FilteredLines.push_back(MCCVLoc(MCCVLines[Idx].getLabel(), FuncId, 305*5f757f3fSDimitry Andric IA.File, IA.Line, IA.Col, false, 306*5f757f3fSDimitry Andric false)); 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric return FilteredLines; 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric std::pair<size_t, size_t> CodeViewContext::getLineExtent(unsigned FuncId) { 3150b57cec5SDimitry Andric auto I = MCCVLineStartStop.find(FuncId); 3160b57cec5SDimitry Andric // Return an empty extent if there are no cv_locs for this function id. 3170b57cec5SDimitry Andric if (I == MCCVLineStartStop.end()) 3180b57cec5SDimitry Andric return {~0ULL, 0}; 3190b57cec5SDimitry Andric return I->second; 3200b57cec5SDimitry Andric } 3210b57cec5SDimitry Andric 322*5f757f3fSDimitry Andric std::pair<size_t, size_t> 323*5f757f3fSDimitry Andric CodeViewContext::getLineExtentIncludingInlinees(unsigned FuncId) { 324*5f757f3fSDimitry Andric size_t LocBegin; 325*5f757f3fSDimitry Andric size_t LocEnd; 326*5f757f3fSDimitry Andric std::tie(LocBegin, LocEnd) = getLineExtent(FuncId); 327*5f757f3fSDimitry Andric 328*5f757f3fSDimitry Andric // Include all child inline call sites in our extent. 329*5f757f3fSDimitry Andric MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(FuncId); 330*5f757f3fSDimitry Andric if (SiteInfo) { 331*5f757f3fSDimitry Andric for (auto &KV : SiteInfo->InlinedAtMap) { 332*5f757f3fSDimitry Andric unsigned ChildId = KV.first; 333*5f757f3fSDimitry Andric auto Extent = getLineExtent(ChildId); 334*5f757f3fSDimitry Andric LocBegin = std::min(LocBegin, Extent.first); 335*5f757f3fSDimitry Andric LocEnd = std::max(LocEnd, Extent.second); 336*5f757f3fSDimitry Andric } 337*5f757f3fSDimitry Andric } 338*5f757f3fSDimitry Andric 339*5f757f3fSDimitry Andric return {LocBegin, LocEnd}; 340*5f757f3fSDimitry Andric } 341*5f757f3fSDimitry Andric 3420b57cec5SDimitry Andric ArrayRef<MCCVLoc> CodeViewContext::getLinesForExtent(size_t L, size_t R) { 3430b57cec5SDimitry Andric if (R <= L) 344bdd1243dSDimitry Andric return std::nullopt; 3450b57cec5SDimitry Andric if (L >= MCCVLines.size()) 346bdd1243dSDimitry Andric return std::nullopt; 347bdd1243dSDimitry Andric return ArrayRef(&MCCVLines[L], R - L); 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, 3510b57cec5SDimitry Andric unsigned FuncId, 3520b57cec5SDimitry Andric const MCSymbol *FuncBegin, 3530b57cec5SDimitry Andric const MCSymbol *FuncEnd) { 3540b57cec5SDimitry Andric MCContext &Ctx = OS.getContext(); 3550b57cec5SDimitry Andric MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin", false), 3560b57cec5SDimitry Andric *LineEnd = Ctx.createTempSymbol("linetable_end", false); 3570b57cec5SDimitry Andric 3585ffd83dbSDimitry Andric OS.emitInt32(uint32_t(DebugSubsectionKind::Lines)); 3590b57cec5SDimitry Andric OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4); 3605ffd83dbSDimitry Andric OS.emitLabel(LineBegin); 36181ad6265SDimitry Andric OS.emitCOFFSecRel32(FuncBegin, /*Offset=*/0); 36281ad6265SDimitry Andric OS.emitCOFFSectionIndex(FuncBegin); 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric // Actual line info. 3650b57cec5SDimitry Andric std::vector<MCCVLoc> Locs = getFunctionLineEntries(FuncId); 3660b57cec5SDimitry Andric bool HaveColumns = any_of(Locs, [](const MCCVLoc &LineEntry) { 3670b57cec5SDimitry Andric return LineEntry.getColumn() != 0; 3680b57cec5SDimitry Andric }); 3695ffd83dbSDimitry Andric OS.emitInt16(HaveColumns ? int(LF_HaveColumns) : 0); 3700b57cec5SDimitry Andric OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4); 3710b57cec5SDimitry Andric 3720b57cec5SDimitry Andric for (auto I = Locs.begin(), E = Locs.end(); I != E;) { 3730b57cec5SDimitry Andric // Emit a file segment for the run of locations that share a file id. 3740b57cec5SDimitry Andric unsigned CurFileNum = I->getFileNum(); 3750b57cec5SDimitry Andric auto FileSegEnd = 3760b57cec5SDimitry Andric std::find_if(I, E, [CurFileNum](const MCCVLoc &Loc) { 3770b57cec5SDimitry Andric return Loc.getFileNum() != CurFileNum; 3780b57cec5SDimitry Andric }); 3790b57cec5SDimitry Andric unsigned EntryCount = FileSegEnd - I; 3800b57cec5SDimitry Andric OS.AddComment( 3810b57cec5SDimitry Andric "Segment for file '" + 3820b57cec5SDimitry Andric Twine(getStringTableFragment() 3830b57cec5SDimitry Andric ->getContents()[Files[CurFileNum - 1].StringTableOffset]) + 3840b57cec5SDimitry Andric "' begins"); 3855ffd83dbSDimitry Andric OS.emitCVFileChecksumOffsetDirective(CurFileNum); 3865ffd83dbSDimitry Andric OS.emitInt32(EntryCount); 3870b57cec5SDimitry Andric uint32_t SegmentSize = 12; 3880b57cec5SDimitry Andric SegmentSize += 8 * EntryCount; 3890b57cec5SDimitry Andric if (HaveColumns) 3900b57cec5SDimitry Andric SegmentSize += 4 * EntryCount; 3915ffd83dbSDimitry Andric OS.emitInt32(SegmentSize); 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric for (auto J = I; J != FileSegEnd; ++J) { 3940b57cec5SDimitry Andric OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4); 3950b57cec5SDimitry Andric unsigned LineData = J->getLine(); 3960b57cec5SDimitry Andric if (J->isStmt()) 3970b57cec5SDimitry Andric LineData |= LineInfo::StatementFlag; 3985ffd83dbSDimitry Andric OS.emitInt32(LineData); 3990b57cec5SDimitry Andric } 4000b57cec5SDimitry Andric if (HaveColumns) { 4010b57cec5SDimitry Andric for (auto J = I; J != FileSegEnd; ++J) { 4025ffd83dbSDimitry Andric OS.emitInt16(J->getColumn()); 4035ffd83dbSDimitry Andric OS.emitInt16(0); 4040b57cec5SDimitry Andric } 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric I = FileSegEnd; 4070b57cec5SDimitry Andric } 4085ffd83dbSDimitry Andric OS.emitLabel(LineEnd); 4090b57cec5SDimitry Andric } 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric static bool compressAnnotation(uint32_t Data, SmallVectorImpl<char> &Buffer) { 4120b57cec5SDimitry Andric if (isUInt<7>(Data)) { 4130b57cec5SDimitry Andric Buffer.push_back(Data); 4140b57cec5SDimitry Andric return true; 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric if (isUInt<14>(Data)) { 4180b57cec5SDimitry Andric Buffer.push_back((Data >> 8) | 0x80); 4190b57cec5SDimitry Andric Buffer.push_back(Data & 0xff); 4200b57cec5SDimitry Andric return true; 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric 4230b57cec5SDimitry Andric if (isUInt<29>(Data)) { 4240b57cec5SDimitry Andric Buffer.push_back((Data >> 24) | 0xC0); 4250b57cec5SDimitry Andric Buffer.push_back((Data >> 16) & 0xff); 4260b57cec5SDimitry Andric Buffer.push_back((Data >> 8) & 0xff); 4270b57cec5SDimitry Andric Buffer.push_back(Data & 0xff); 4280b57cec5SDimitry Andric return true; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric return false; 4320b57cec5SDimitry Andric } 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric static bool compressAnnotation(BinaryAnnotationsOpCode Annotation, 4350b57cec5SDimitry Andric SmallVectorImpl<char> &Buffer) { 4360b57cec5SDimitry Andric return compressAnnotation(static_cast<uint32_t>(Annotation), Buffer); 4370b57cec5SDimitry Andric } 4380b57cec5SDimitry Andric 4390b57cec5SDimitry Andric static uint32_t encodeSignedNumber(uint32_t Data) { 4400b57cec5SDimitry Andric if (Data >> 31) 4410b57cec5SDimitry Andric return ((-Data) << 1) | 1; 4420b57cec5SDimitry Andric return Data << 1; 4430b57cec5SDimitry Andric } 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS, 4460b57cec5SDimitry Andric unsigned PrimaryFunctionId, 4470b57cec5SDimitry Andric unsigned SourceFileId, 4480b57cec5SDimitry Andric unsigned SourceLineNum, 4490b57cec5SDimitry Andric const MCSymbol *FnStartSym, 4500b57cec5SDimitry Andric const MCSymbol *FnEndSym) { 4510b57cec5SDimitry Andric // Create and insert a fragment into the current section that will be encoded 4520b57cec5SDimitry Andric // later. 4530b57cec5SDimitry Andric new MCCVInlineLineTableFragment(PrimaryFunctionId, SourceFileId, 4540b57cec5SDimitry Andric SourceLineNum, FnStartSym, FnEndSym, 4550b57cec5SDimitry Andric OS.getCurrentSectionOnly()); 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric MCFragment *CodeViewContext::emitDefRange( 4590b57cec5SDimitry Andric MCObjectStreamer &OS, 4600b57cec5SDimitry Andric ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, 4610b57cec5SDimitry Andric StringRef FixedSizePortion) { 4620b57cec5SDimitry Andric // Create and insert a fragment into the current section that will be encoded 4630b57cec5SDimitry Andric // later. 4640b57cec5SDimitry Andric return new MCCVDefRangeFragment(Ranges, FixedSizePortion, 4650b57cec5SDimitry Andric OS.getCurrentSectionOnly()); 4660b57cec5SDimitry Andric } 4670b57cec5SDimitry Andric 4680b57cec5SDimitry Andric static unsigned computeLabelDiff(MCAsmLayout &Layout, const MCSymbol *Begin, 4690b57cec5SDimitry Andric const MCSymbol *End) { 4700b57cec5SDimitry Andric MCContext &Ctx = Layout.getAssembler().getContext(); 4710b57cec5SDimitry Andric MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; 4720b57cec5SDimitry Andric const MCExpr *BeginRef = MCSymbolRefExpr::create(Begin, Variant, Ctx), 4730b57cec5SDimitry Andric *EndRef = MCSymbolRefExpr::create(End, Variant, Ctx); 4740b57cec5SDimitry Andric const MCExpr *AddrDelta = 4750b57cec5SDimitry Andric MCBinaryExpr::create(MCBinaryExpr::Sub, EndRef, BeginRef, Ctx); 4760b57cec5SDimitry Andric int64_t Result; 4770b57cec5SDimitry Andric bool Success = AddrDelta->evaluateKnownAbsolute(Result, Layout); 4780b57cec5SDimitry Andric assert(Success && "failed to evaluate label difference as absolute"); 4790b57cec5SDimitry Andric (void)Success; 4800b57cec5SDimitry Andric assert(Result >= 0 && "negative label difference requested"); 4810b57cec5SDimitry Andric assert(Result < UINT_MAX && "label difference greater than 2GB"); 4820b57cec5SDimitry Andric return unsigned(Result); 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, 4860b57cec5SDimitry Andric MCCVInlineLineTableFragment &Frag) { 4870b57cec5SDimitry Andric size_t LocBegin; 4880b57cec5SDimitry Andric size_t LocEnd; 489*5f757f3fSDimitry Andric std::tie(LocBegin, LocEnd) = getLineExtentIncludingInlinees(Frag.SiteFuncId); 4900b57cec5SDimitry Andric 4910b57cec5SDimitry Andric if (LocBegin >= LocEnd) 4920b57cec5SDimitry Andric return; 4930b57cec5SDimitry Andric ArrayRef<MCCVLoc> Locs = getLinesForExtent(LocBegin, LocEnd); 4940b57cec5SDimitry Andric if (Locs.empty()) 4950b57cec5SDimitry Andric return; 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric // Check that the locations are all in the same section. 4980b57cec5SDimitry Andric #ifndef NDEBUG 4990b57cec5SDimitry Andric const MCSection *FirstSec = &Locs.front().getLabel()->getSection(); 5000b57cec5SDimitry Andric for (const MCCVLoc &Loc : Locs) { 5010b57cec5SDimitry Andric if (&Loc.getLabel()->getSection() != FirstSec) { 5020b57cec5SDimitry Andric errs() << ".cv_loc " << Loc.getFunctionId() << ' ' << Loc.getFileNum() 5030b57cec5SDimitry Andric << ' ' << Loc.getLine() << ' ' << Loc.getColumn() 5040b57cec5SDimitry Andric << " is in the wrong section\n"; 5050b57cec5SDimitry Andric llvm_unreachable(".cv_loc crosses sections"); 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric } 5080b57cec5SDimitry Andric #endif 5090b57cec5SDimitry Andric 5100b57cec5SDimitry Andric // Make an artificial start location using the function start and the inlinee 5110b57cec5SDimitry Andric // lines start location information. All deltas start relative to this 5120b57cec5SDimitry Andric // location. 5130b57cec5SDimitry Andric MCCVLoc StartLoc = Locs.front(); 5140b57cec5SDimitry Andric StartLoc.setLabel(Frag.getFnStartSym()); 5150b57cec5SDimitry Andric StartLoc.setFileNum(Frag.StartFileId); 5160b57cec5SDimitry Andric StartLoc.setLine(Frag.StartLineNum); 5170b57cec5SDimitry Andric bool HaveOpenRange = false; 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric const MCSymbol *LastLabel = Frag.getFnStartSym(); 5200b57cec5SDimitry Andric MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc; 5210b57cec5SDimitry Andric LastSourceLoc.File = Frag.StartFileId; 5220b57cec5SDimitry Andric LastSourceLoc.Line = Frag.StartLineNum; 5230b57cec5SDimitry Andric 524*5f757f3fSDimitry Andric MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId); 525*5f757f3fSDimitry Andric 5260b57cec5SDimitry Andric SmallVectorImpl<char> &Buffer = Frag.getContents(); 5270b57cec5SDimitry Andric Buffer.clear(); // Clear old contents if we went through relaxation. 5280b57cec5SDimitry Andric for (const MCCVLoc &Loc : Locs) { 5290b57cec5SDimitry Andric // Exit early if our line table would produce an oversized InlineSiteSym 5300b57cec5SDimitry Andric // record. Account for the ChangeCodeLength annotation emitted after the 5310b57cec5SDimitry Andric // loop ends. 5320b57cec5SDimitry Andric constexpr uint32_t InlineSiteSize = 12; 5330b57cec5SDimitry Andric constexpr uint32_t AnnotationSize = 8; 5340b57cec5SDimitry Andric size_t MaxBufferSize = MaxRecordLength - InlineSiteSize - AnnotationSize; 5350b57cec5SDimitry Andric if (Buffer.size() >= MaxBufferSize) 5360b57cec5SDimitry Andric break; 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andric if (Loc.getFunctionId() == Frag.SiteFuncId) { 5390b57cec5SDimitry Andric CurSourceLoc.File = Loc.getFileNum(); 5400b57cec5SDimitry Andric CurSourceLoc.Line = Loc.getLine(); 5410b57cec5SDimitry Andric } else { 5420b57cec5SDimitry Andric auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId()); 5430b57cec5SDimitry Andric if (I != SiteInfo->InlinedAtMap.end()) { 5440b57cec5SDimitry Andric // This .cv_loc is from a child inline call site. Use the source 5450b57cec5SDimitry Andric // location of the inlined call site instead of the .cv_loc directive 5460b57cec5SDimitry Andric // source location. 5470b57cec5SDimitry Andric CurSourceLoc = I->second; 5480b57cec5SDimitry Andric } else { 5490b57cec5SDimitry Andric // We've hit a cv_loc not attributed to this inline call site. Use this 5500b57cec5SDimitry Andric // label to end the PC range. 5510b57cec5SDimitry Andric if (HaveOpenRange) { 5520b57cec5SDimitry Andric unsigned Length = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); 5530b57cec5SDimitry Andric compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer); 5540b57cec5SDimitry Andric compressAnnotation(Length, Buffer); 5550b57cec5SDimitry Andric LastLabel = Loc.getLabel(); 5560b57cec5SDimitry Andric } 5570b57cec5SDimitry Andric HaveOpenRange = false; 5580b57cec5SDimitry Andric continue; 5590b57cec5SDimitry Andric } 5600b57cec5SDimitry Andric } 5610b57cec5SDimitry Andric 5620b57cec5SDimitry Andric // Skip this .cv_loc if we have an open range and this isn't a meaningful 5630b57cec5SDimitry Andric // source location update. The current table format does not support column 5640b57cec5SDimitry Andric // info, so we can skip updates for those. 5650b57cec5SDimitry Andric if (HaveOpenRange && CurSourceLoc.File == LastSourceLoc.File && 5660b57cec5SDimitry Andric CurSourceLoc.Line == LastSourceLoc.Line) 5670b57cec5SDimitry Andric continue; 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric HaveOpenRange = true; 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric if (CurSourceLoc.File != LastSourceLoc.File) { 5720b57cec5SDimitry Andric unsigned FileOffset = static_cast<const MCConstantExpr *>( 5730b57cec5SDimitry Andric Files[CurSourceLoc.File - 1] 5740b57cec5SDimitry Andric .ChecksumTableOffset->getVariableValue()) 5750b57cec5SDimitry Andric ->getValue(); 5760b57cec5SDimitry Andric compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer); 5770b57cec5SDimitry Andric compressAnnotation(FileOffset, Buffer); 5780b57cec5SDimitry Andric } 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line; 5810b57cec5SDimitry Andric unsigned EncodedLineDelta = encodeSignedNumber(LineDelta); 5820b57cec5SDimitry Andric unsigned CodeDelta = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); 583e8d8bef9SDimitry Andric if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) { 5840b57cec5SDimitry Andric // The ChangeCodeOffsetAndLineOffset combination opcode is used when the 5850b57cec5SDimitry Andric // encoded line delta uses 3 or fewer set bits and the code offset fits 5860b57cec5SDimitry Andric // in one nibble. 5870b57cec5SDimitry Andric unsigned Operand = (EncodedLineDelta << 4) | CodeDelta; 5880b57cec5SDimitry Andric compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset, 5890b57cec5SDimitry Andric Buffer); 5900b57cec5SDimitry Andric compressAnnotation(Operand, Buffer); 5910b57cec5SDimitry Andric } else { 5920b57cec5SDimitry Andric // Otherwise use the separate line and code deltas. 5930b57cec5SDimitry Andric if (LineDelta != 0) { 5940b57cec5SDimitry Andric compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer); 5950b57cec5SDimitry Andric compressAnnotation(EncodedLineDelta, Buffer); 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffset, Buffer); 5980b57cec5SDimitry Andric compressAnnotation(CodeDelta, Buffer); 5990b57cec5SDimitry Andric } 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric LastLabel = Loc.getLabel(); 6020b57cec5SDimitry Andric LastSourceLoc = CurSourceLoc; 6030b57cec5SDimitry Andric } 6040b57cec5SDimitry Andric 6050b57cec5SDimitry Andric assert(HaveOpenRange); 6060b57cec5SDimitry Andric 6070b57cec5SDimitry Andric unsigned EndSymLength = 6080b57cec5SDimitry Andric computeLabelDiff(Layout, LastLabel, Frag.getFnEndSym()); 6090b57cec5SDimitry Andric unsigned LocAfterLength = ~0U; 6100b57cec5SDimitry Andric ArrayRef<MCCVLoc> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1); 6110b57cec5SDimitry Andric if (!LocAfter.empty()) { 6120b57cec5SDimitry Andric // Only try to compute this difference if we're in the same section. 6130b57cec5SDimitry Andric const MCCVLoc &Loc = LocAfter[0]; 6140b57cec5SDimitry Andric if (&Loc.getLabel()->getSection() == &LastLabel->getSection()) 6150b57cec5SDimitry Andric LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); 6160b57cec5SDimitry Andric } 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer); 6190b57cec5SDimitry Andric compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer); 6200b57cec5SDimitry Andric } 6210b57cec5SDimitry Andric 6220b57cec5SDimitry Andric void CodeViewContext::encodeDefRange(MCAsmLayout &Layout, 6230b57cec5SDimitry Andric MCCVDefRangeFragment &Frag) { 6240b57cec5SDimitry Andric MCContext &Ctx = Layout.getAssembler().getContext(); 6250b57cec5SDimitry Andric SmallVectorImpl<char> &Contents = Frag.getContents(); 6260b57cec5SDimitry Andric Contents.clear(); 6270b57cec5SDimitry Andric SmallVectorImpl<MCFixup> &Fixups = Frag.getFixups(); 6280b57cec5SDimitry Andric Fixups.clear(); 6290b57cec5SDimitry Andric raw_svector_ostream OS(Contents); 6300b57cec5SDimitry Andric 6310b57cec5SDimitry Andric // Compute all the sizes up front. 6320b57cec5SDimitry Andric SmallVector<std::pair<unsigned, unsigned>, 4> GapAndRangeSizes; 6330b57cec5SDimitry Andric const MCSymbol *LastLabel = nullptr; 6340b57cec5SDimitry Andric for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) { 6350b57cec5SDimitry Andric unsigned GapSize = 6360b57cec5SDimitry Andric LastLabel ? computeLabelDiff(Layout, LastLabel, Range.first) : 0; 6370b57cec5SDimitry Andric unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second); 6380b57cec5SDimitry Andric GapAndRangeSizes.push_back({GapSize, RangeSize}); 6390b57cec5SDimitry Andric LastLabel = Range.second; 6400b57cec5SDimitry Andric } 6410b57cec5SDimitry Andric 6420b57cec5SDimitry Andric // Write down each range where the variable is defined. 6430b57cec5SDimitry Andric for (size_t I = 0, E = Frag.getRanges().size(); I != E;) { 6440b57cec5SDimitry Andric // If the range size of multiple consecutive ranges is under the max, 6450b57cec5SDimitry Andric // combine the ranges and emit some gaps. 6460b57cec5SDimitry Andric const MCSymbol *RangeBegin = Frag.getRanges()[I].first; 6470b57cec5SDimitry Andric unsigned RangeSize = GapAndRangeSizes[I].second; 6480b57cec5SDimitry Andric size_t J = I + 1; 6490b57cec5SDimitry Andric for (; J != E; ++J) { 6500b57cec5SDimitry Andric unsigned GapAndRangeSize = GapAndRangeSizes[J].first + GapAndRangeSizes[J].second; 6510b57cec5SDimitry Andric if (RangeSize + GapAndRangeSize > MaxDefRange) 6520b57cec5SDimitry Andric break; 6530b57cec5SDimitry Andric RangeSize += GapAndRangeSize; 6540b57cec5SDimitry Andric } 6550b57cec5SDimitry Andric unsigned NumGaps = J - I - 1; 6560b57cec5SDimitry Andric 657*5f757f3fSDimitry Andric support::endian::Writer LEWriter(OS, llvm::endianness::little); 6580b57cec5SDimitry Andric 6590b57cec5SDimitry Andric unsigned Bias = 0; 6600b57cec5SDimitry Andric // We must split the range into chunks of MaxDefRange, this is a fundamental 6610b57cec5SDimitry Andric // limitation of the file format. 6620b57cec5SDimitry Andric do { 6630b57cec5SDimitry Andric uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize); 6640b57cec5SDimitry Andric 6650b57cec5SDimitry Andric const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(RangeBegin, Ctx); 6660b57cec5SDimitry Andric const MCBinaryExpr *BE = 6670b57cec5SDimitry Andric MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx); 6680b57cec5SDimitry Andric 6690b57cec5SDimitry Andric // Each record begins with a 2-byte number indicating how large the record 6700b57cec5SDimitry Andric // is. 6710b57cec5SDimitry Andric StringRef FixedSizePortion = Frag.getFixedSizePortion(); 6720b57cec5SDimitry Andric // Our record is a fixed sized prefix and a LocalVariableAddrRange that we 6730b57cec5SDimitry Andric // are artificially constructing. 6740b57cec5SDimitry Andric size_t RecordSize = FixedSizePortion.size() + 6750b57cec5SDimitry Andric sizeof(LocalVariableAddrRange) + 4 * NumGaps; 6760b57cec5SDimitry Andric // Write out the record size. 6770b57cec5SDimitry Andric LEWriter.write<uint16_t>(RecordSize); 6780b57cec5SDimitry Andric // Write out the fixed size prefix. 6790b57cec5SDimitry Andric OS << FixedSizePortion; 6800b57cec5SDimitry Andric // Make space for a fixup that will eventually have a section relative 6810b57cec5SDimitry Andric // relocation pointing at the offset where the variable becomes live. 6820b57cec5SDimitry Andric Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4)); 6830b57cec5SDimitry Andric LEWriter.write<uint32_t>(0); // Fixup for code start. 6840b57cec5SDimitry Andric // Make space for a fixup that will record the section index for the code. 6850b57cec5SDimitry Andric Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2)); 6860b57cec5SDimitry Andric LEWriter.write<uint16_t>(0); // Fixup for section index. 6870b57cec5SDimitry Andric // Write down the range's extent. 6880b57cec5SDimitry Andric LEWriter.write<uint16_t>(Chunk); 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric // Move on to the next range. 6910b57cec5SDimitry Andric Bias += Chunk; 6920b57cec5SDimitry Andric RangeSize -= Chunk; 6930b57cec5SDimitry Andric } while (RangeSize > 0); 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric // Emit the gaps afterwards. 6960b57cec5SDimitry Andric assert((NumGaps == 0 || Bias <= MaxDefRange) && 6970b57cec5SDimitry Andric "large ranges should not have gaps"); 6980b57cec5SDimitry Andric unsigned GapStartOffset = GapAndRangeSizes[I].second; 6990b57cec5SDimitry Andric for (++I; I != J; ++I) { 7000b57cec5SDimitry Andric unsigned GapSize, RangeSize; 7010b57cec5SDimitry Andric assert(I < GapAndRangeSizes.size()); 7020b57cec5SDimitry Andric std::tie(GapSize, RangeSize) = GapAndRangeSizes[I]; 7030b57cec5SDimitry Andric LEWriter.write<uint16_t>(GapStartOffset); 7040b57cec5SDimitry Andric LEWriter.write<uint16_t>(GapSize); 7050b57cec5SDimitry Andric GapStartOffset += GapSize + RangeSize; 7060b57cec5SDimitry Andric } 7070b57cec5SDimitry Andric } 7080b57cec5SDimitry Andric } 709