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