12214ed89SReid Kleckner //===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===// 22214ed89SReid Kleckner // 32214ed89SReid Kleckner // The LLVM Compiler Infrastructure 42214ed89SReid Kleckner // 52214ed89SReid Kleckner // This file is distributed under the University of Illinois Open Source 62214ed89SReid Kleckner // License. See LICENSE.TXT for details. 72214ed89SReid Kleckner // 82214ed89SReid Kleckner //===----------------------------------------------------------------------===// 92214ed89SReid Kleckner // 102214ed89SReid Kleckner // Holds state from .cv_file and .cv_loc directives for later emission. 112214ed89SReid Kleckner // 122214ed89SReid Kleckner //===----------------------------------------------------------------------===// 132214ed89SReid Kleckner 142214ed89SReid Kleckner #include "llvm/MC/MCCodeView.h" 152214ed89SReid Kleckner #include "llvm/ADT/STLExtras.h" 1626fa1bf4SReid Kleckner #include "llvm/ADT/StringExtras.h" 172214ed89SReid Kleckner #include "llvm/DebugInfo/CodeView/CodeView.h" 182214ed89SReid Kleckner #include "llvm/DebugInfo/CodeView/Line.h" 196fcbd7e9SDavid Majnemer #include "llvm/DebugInfo/CodeView/SymbolRecord.h" 20d427383cSZachary Turner #include "llvm/MC/MCAsmLayout.h" 212214ed89SReid Kleckner #include "llvm/MC/MCContext.h" 222214ed89SReid Kleckner #include "llvm/MC/MCObjectStreamer.h" 23408b5e66SDavid Majnemer #include "llvm/MC/MCValue.h" 24858239d5SReid Kleckner #include "llvm/Support/EndianStream.h" 252214ed89SReid Kleckner 262214ed89SReid Kleckner using namespace llvm; 272214ed89SReid Kleckner using namespace llvm::codeview; 282214ed89SReid Kleckner 292214ed89SReid Kleckner CodeViewContext::CodeViewContext() {} 302214ed89SReid Kleckner 312214ed89SReid Kleckner CodeViewContext::~CodeViewContext() { 322214ed89SReid Kleckner // If someone inserted strings into the string table but never actually 332214ed89SReid Kleckner // emitted them somewhere, clean up the fragment. 342214ed89SReid Kleckner if (!InsertedStrTabFragment) 352214ed89SReid Kleckner delete StrTabFragment; 362214ed89SReid Kleckner } 372214ed89SReid Kleckner 382214ed89SReid Kleckner /// This is a valid number for use with .cv_loc if we've already seen a .cv_file 392214ed89SReid Kleckner /// for it. 402214ed89SReid Kleckner bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const { 412214ed89SReid Kleckner unsigned Idx = FileNumber - 1; 4226fa1bf4SReid Kleckner if (Idx < Files.size()) 4326fa1bf4SReid Kleckner return Files[Idx].Assigned; 442214ed89SReid Kleckner return false; 452214ed89SReid Kleckner } 462214ed89SReid Kleckner 4726fa1bf4SReid Kleckner bool CodeViewContext::addFile(MCStreamer &OS, unsigned FileNumber, 4826fa1bf4SReid Kleckner StringRef Filename, 4926fa1bf4SReid Kleckner ArrayRef<uint8_t> ChecksumBytes, 5026fa1bf4SReid Kleckner uint8_t ChecksumKind) { 512214ed89SReid Kleckner assert(FileNumber > 0); 5226fa1bf4SReid Kleckner auto FilenameOffset = addToStringTable(Filename); 5326fa1bf4SReid Kleckner Filename = FilenameOffset.first; 542214ed89SReid Kleckner unsigned Idx = FileNumber - 1; 5526fa1bf4SReid Kleckner if (Idx >= Files.size()) 5626fa1bf4SReid Kleckner Files.resize(Idx + 1); 572214ed89SReid Kleckner 582214ed89SReid Kleckner if (Filename.empty()) 592214ed89SReid Kleckner Filename = "<stdin>"; 602214ed89SReid Kleckner 6126fa1bf4SReid Kleckner if (Files[Idx].Assigned) 622214ed89SReid Kleckner return false; 632214ed89SReid Kleckner 6426fa1bf4SReid Kleckner FilenameOffset = addToStringTable(Filename); 6526fa1bf4SReid Kleckner Filename = FilenameOffset.first; 6626fa1bf4SReid Kleckner unsigned Offset = FilenameOffset.second; 672214ed89SReid Kleckner 6826fa1bf4SReid Kleckner auto ChecksumOffsetSymbol = 6926fa1bf4SReid Kleckner OS.getContext().createTempSymbol("checksum_offset", false); 7026fa1bf4SReid Kleckner Files[Idx].StringTableOffset = Offset; 7126fa1bf4SReid Kleckner Files[Idx].ChecksumTableOffset = ChecksumOffsetSymbol; 7226fa1bf4SReid Kleckner Files[Idx].Assigned = true; 7326fa1bf4SReid Kleckner Files[Idx].Checksum = ChecksumBytes; 7426fa1bf4SReid Kleckner Files[Idx].ChecksumKind = ChecksumKind; 7526fa1bf4SReid Kleckner 762214ed89SReid Kleckner return true; 772214ed89SReid Kleckner } 782214ed89SReid Kleckner 79*b5258722SReid Kleckner MCCVFunctionInfo *CodeViewContext::getCVFunctionInfo(unsigned FuncId) { 80*b5258722SReid Kleckner if (FuncId >= Functions.size()) 81*b5258722SReid Kleckner return nullptr; 82*b5258722SReid Kleckner if (Functions[FuncId].isUnallocatedFunctionInfo()) 83*b5258722SReid Kleckner return nullptr; 84*b5258722SReid Kleckner return &Functions[FuncId]; 85*b5258722SReid Kleckner } 86*b5258722SReid Kleckner 87a9f4cc95SReid Kleckner bool CodeViewContext::recordFunctionId(unsigned FuncId) { 88a9f4cc95SReid Kleckner if (FuncId >= Functions.size()) 89a9f4cc95SReid Kleckner Functions.resize(FuncId + 1); 90a9f4cc95SReid Kleckner 91a9f4cc95SReid Kleckner // Return false if this function info was already allocated. 92a9f4cc95SReid Kleckner if (!Functions[FuncId].isUnallocatedFunctionInfo()) 93a9f4cc95SReid Kleckner return false; 94a9f4cc95SReid Kleckner 95a9f4cc95SReid Kleckner // Mark this as an allocated normal function, and leave the rest alone. 96a9f4cc95SReid Kleckner Functions[FuncId].ParentFuncIdPlusOne = MCCVFunctionInfo::FunctionSentinel; 97a9f4cc95SReid Kleckner return true; 98a9f4cc95SReid Kleckner } 99a9f4cc95SReid Kleckner 100a9f4cc95SReid Kleckner bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc, 101a9f4cc95SReid Kleckner unsigned IAFile, unsigned IALine, 102a9f4cc95SReid Kleckner unsigned IACol) { 103a9f4cc95SReid Kleckner if (FuncId >= Functions.size()) 104a9f4cc95SReid Kleckner Functions.resize(FuncId + 1); 105a9f4cc95SReid Kleckner 106a9f4cc95SReid Kleckner // Return false if this function info was already allocated. 107a9f4cc95SReid Kleckner if (!Functions[FuncId].isUnallocatedFunctionInfo()) 108a9f4cc95SReid Kleckner return false; 109a9f4cc95SReid Kleckner 110a9f4cc95SReid Kleckner MCCVFunctionInfo::LineInfo InlinedAt; 111a9f4cc95SReid Kleckner InlinedAt.File = IAFile; 112a9f4cc95SReid Kleckner InlinedAt.Line = IALine; 113a9f4cc95SReid Kleckner InlinedAt.Col = IACol; 114a9f4cc95SReid Kleckner 115a9f4cc95SReid Kleckner // Mark this as an inlined call site and record call site line info. 116a9f4cc95SReid Kleckner MCCVFunctionInfo *Info = &Functions[FuncId]; 117a9f4cc95SReid Kleckner Info->ParentFuncIdPlusOne = IAFunc + 1; 118a9f4cc95SReid Kleckner Info->InlinedAt = InlinedAt; 119a9f4cc95SReid Kleckner 120a9f4cc95SReid Kleckner // Walk up the call chain adding this function id to the InlinedAtMap of all 121a9f4cc95SReid Kleckner // transitive callers until we hit a real function. 122a9f4cc95SReid Kleckner while (Info->isInlinedCallSite()) { 123a9f4cc95SReid Kleckner InlinedAt = Info->InlinedAt; 124a9f4cc95SReid Kleckner Info = getCVFunctionInfo(Info->getParentFuncId()); 125a9f4cc95SReid Kleckner Info->InlinedAtMap[FuncId] = InlinedAt; 126a9f4cc95SReid Kleckner } 127a9f4cc95SReid Kleckner 128a9f4cc95SReid Kleckner return true; 129a9f4cc95SReid Kleckner } 130a9f4cc95SReid Kleckner 1312214ed89SReid Kleckner MCDataFragment *CodeViewContext::getStringTableFragment() { 1322214ed89SReid Kleckner if (!StrTabFragment) { 1332214ed89SReid Kleckner StrTabFragment = new MCDataFragment(); 1342214ed89SReid Kleckner // Start a new string table out with a null byte. 1352214ed89SReid Kleckner StrTabFragment->getContents().push_back('\0'); 1362214ed89SReid Kleckner } 1372214ed89SReid Kleckner return StrTabFragment; 1382214ed89SReid Kleckner } 1392214ed89SReid Kleckner 14026fa1bf4SReid Kleckner std::pair<StringRef, unsigned> CodeViewContext::addToStringTable(StringRef S) { 1412214ed89SReid Kleckner SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents(); 1422214ed89SReid Kleckner auto Insertion = 1432214ed89SReid Kleckner StringTable.insert(std::make_pair(S, unsigned(Contents.size()))); 1442214ed89SReid Kleckner // Return the string from the table, since it is stable. 14526fa1bf4SReid Kleckner std::pair<StringRef, unsigned> Ret = 14626fa1bf4SReid Kleckner std::make_pair(Insertion.first->first(), Insertion.first->second); 1472214ed89SReid Kleckner if (Insertion.second) { 1482214ed89SReid Kleckner // The string map key is always null terminated. 14926fa1bf4SReid Kleckner Contents.append(Ret.first.begin(), Ret.first.end() + 1); 1502214ed89SReid Kleckner } 15126fa1bf4SReid Kleckner return Ret; 1522214ed89SReid Kleckner } 1532214ed89SReid Kleckner 1542214ed89SReid Kleckner unsigned CodeViewContext::getStringTableOffset(StringRef S) { 1552214ed89SReid Kleckner // A string table offset of zero is always the empty string. 1562214ed89SReid Kleckner if (S.empty()) 1572214ed89SReid Kleckner return 0; 1582214ed89SReid Kleckner auto I = StringTable.find(S); 1592214ed89SReid Kleckner assert(I != StringTable.end()); 1602214ed89SReid Kleckner return I->second; 1612214ed89SReid Kleckner } 1622214ed89SReid Kleckner 1632214ed89SReid Kleckner void CodeViewContext::emitStringTable(MCObjectStreamer &OS) { 1642214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 165a0b44ef6SDavid Blaikie MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin", false), 166a0b44ef6SDavid Blaikie *StringEnd = Ctx.createTempSymbol("strtab_end", false); 1672214ed89SReid Kleckner 1688c099fe0SZachary Turner OS.EmitIntValue(unsigned(DebugSubsectionKind::StringTable), 4); 1692214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4); 1702214ed89SReid Kleckner OS.EmitLabel(StringBegin); 1712214ed89SReid Kleckner 1722214ed89SReid Kleckner // Put the string table data fragment here, if we haven't already put it 1732214ed89SReid Kleckner // somewhere else. If somebody wants two string tables in their .s file, one 1742214ed89SReid Kleckner // will just be empty. 1752214ed89SReid Kleckner if (!InsertedStrTabFragment) { 1762214ed89SReid Kleckner OS.insert(getStringTableFragment()); 1772214ed89SReid Kleckner InsertedStrTabFragment = true; 1782214ed89SReid Kleckner } 1792214ed89SReid Kleckner 1802214ed89SReid Kleckner OS.EmitValueToAlignment(4, 0); 1812214ed89SReid Kleckner 1822214ed89SReid Kleckner OS.EmitLabel(StringEnd); 1832214ed89SReid Kleckner } 1842214ed89SReid Kleckner 1852214ed89SReid Kleckner void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) { 186ee641c20SReid Kleckner // Do nothing if there are no file checksums. Microsoft's linker rejects empty 187ee641c20SReid Kleckner // CodeView substreams. 18826fa1bf4SReid Kleckner if (Files.empty()) 189ee641c20SReid Kleckner return; 190ee641c20SReid Kleckner 1912214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 192a0b44ef6SDavid Blaikie MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin", false), 193a0b44ef6SDavid Blaikie *FileEnd = Ctx.createTempSymbol("filechecksums_end", false); 1942214ed89SReid Kleckner 1958c099fe0SZachary Turner OS.EmitIntValue(unsigned(DebugSubsectionKind::FileChecksums), 4); 1962214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4); 1972214ed89SReid Kleckner OS.EmitLabel(FileBegin); 1982214ed89SReid Kleckner 19926fa1bf4SReid Kleckner unsigned CurrentOffset = 0; 20026fa1bf4SReid Kleckner 2012214ed89SReid Kleckner // Emit an array of FileChecksum entries. We index into this table using the 20226fa1bf4SReid Kleckner // user-provided file number. Each entry may be a variable number of bytes 20326fa1bf4SReid Kleckner // determined by the checksum kind and size. 20426fa1bf4SReid Kleckner for (auto File : Files) { 20526fa1bf4SReid Kleckner OS.EmitAssignment(File.ChecksumTableOffset, 20626fa1bf4SReid Kleckner MCConstantExpr::create(CurrentOffset, Ctx)); 20726fa1bf4SReid Kleckner CurrentOffset += 4; // String table offset. 20826fa1bf4SReid Kleckner if (!File.ChecksumKind) { 20926fa1bf4SReid Kleckner CurrentOffset += 21026fa1bf4SReid Kleckner 4; // One byte each for checksum size and kind, then align to 4 bytes. 21126fa1bf4SReid Kleckner } else { 21226fa1bf4SReid Kleckner CurrentOffset += 2; // One byte each for checksum size and kind. 21326fa1bf4SReid Kleckner CurrentOffset += File.Checksum.size(); 21426fa1bf4SReid Kleckner CurrentOffset = alignTo(CurrentOffset, 4); 21526fa1bf4SReid Kleckner } 21626fa1bf4SReid Kleckner 21726fa1bf4SReid Kleckner OS.EmitIntValue(File.StringTableOffset, 4); 21826fa1bf4SReid Kleckner 21926fa1bf4SReid Kleckner if (!File.ChecksumKind) { 22026fa1bf4SReid Kleckner // There is no checksum. Therefore zero the next two fields and align 22126fa1bf4SReid Kleckner // back to 4 bytes. 2222214ed89SReid Kleckner OS.EmitIntValue(0, 4); 22326fa1bf4SReid Kleckner continue; 22426fa1bf4SReid Kleckner } 22526fa1bf4SReid Kleckner OS.EmitIntValue(static_cast<uint8_t>(File.Checksum.size()), 1); 22626fa1bf4SReid Kleckner OS.EmitIntValue(File.ChecksumKind, 1); 22726fa1bf4SReid Kleckner OS.EmitBytes(toStringRef(File.Checksum)); 22826fa1bf4SReid Kleckner OS.EmitValueToAlignment(4); 2292214ed89SReid Kleckner } 2302214ed89SReid Kleckner 2312214ed89SReid Kleckner OS.EmitLabel(FileEnd); 23226fa1bf4SReid Kleckner 23326fa1bf4SReid Kleckner ChecksumOffsetsAssigned = true; 23426fa1bf4SReid Kleckner } 23526fa1bf4SReid Kleckner 23626fa1bf4SReid Kleckner // Output checksum table offset of the given file number. It is possible that 23726fa1bf4SReid Kleckner // not all files have been registered yet, and so the offset cannot be 23826fa1bf4SReid Kleckner // calculated. In this case a symbol representing the offset is emitted, and 23926fa1bf4SReid Kleckner // the value of this symbol will be fixed up at a later time. 24026fa1bf4SReid Kleckner void CodeViewContext::emitFileChecksumOffset(MCObjectStreamer &OS, 24126fa1bf4SReid Kleckner unsigned FileNo) { 24226fa1bf4SReid Kleckner unsigned Idx = FileNo - 1; 24326fa1bf4SReid Kleckner 24426fa1bf4SReid Kleckner if (Idx >= Files.size()) 24526fa1bf4SReid Kleckner Files.resize(Idx + 1); 24626fa1bf4SReid Kleckner 24726fa1bf4SReid Kleckner if (ChecksumOffsetsAssigned) { 24826fa1bf4SReid Kleckner OS.EmitSymbolValue(Files[Idx].ChecksumTableOffset, 4); 24926fa1bf4SReid Kleckner return; 25026fa1bf4SReid Kleckner } 25126fa1bf4SReid Kleckner 25226fa1bf4SReid Kleckner const MCSymbolRefExpr *SRE = 25326fa1bf4SReid Kleckner MCSymbolRefExpr::create(Files[Idx].ChecksumTableOffset, OS.getContext()); 25426fa1bf4SReid Kleckner 25526fa1bf4SReid Kleckner OS.EmitValueImpl(SRE, 4); 2562214ed89SReid Kleckner } 2572214ed89SReid Kleckner 258*b5258722SReid Kleckner void CodeViewContext::addLineEntry(const MCCVLineEntry &LineEntry) { 259*b5258722SReid Kleckner size_t Offset = MCCVLines.size(); 260*b5258722SReid Kleckner auto I = MCCVLineStartStop.insert( 261*b5258722SReid Kleckner {LineEntry.getFunctionId(), {Offset, Offset + 1}}); 262*b5258722SReid Kleckner if (!I.second) 263*b5258722SReid Kleckner I.first->second.second = Offset + 1; 264*b5258722SReid Kleckner MCCVLines.push_back(LineEntry); 265*b5258722SReid Kleckner } 266*b5258722SReid Kleckner 267*b5258722SReid Kleckner std::vector<MCCVLineEntry> 268*b5258722SReid Kleckner CodeViewContext::getFunctionLineEntries(unsigned FuncId) { 269*b5258722SReid Kleckner std::vector<MCCVLineEntry> FilteredLines; 270*b5258722SReid Kleckner auto I = MCCVLineStartStop.find(FuncId); 271*b5258722SReid Kleckner if (I != MCCVLineStartStop.end()) 272*b5258722SReid Kleckner for (size_t Idx = I->second.first, End = I->second.second; Idx != End; 273*b5258722SReid Kleckner ++Idx) 274*b5258722SReid Kleckner if (MCCVLines[Idx].getFunctionId() == FuncId) 275*b5258722SReid Kleckner FilteredLines.push_back(MCCVLines[Idx]); 276*b5258722SReid Kleckner return FilteredLines; 277*b5258722SReid Kleckner } 278*b5258722SReid Kleckner 279*b5258722SReid Kleckner std::pair<size_t, size_t> CodeViewContext::getLineExtent(unsigned FuncId) { 280*b5258722SReid Kleckner auto I = MCCVLineStartStop.find(FuncId); 281*b5258722SReid Kleckner // Return an empty extent if there are no cv_locs for this function id. 282*b5258722SReid Kleckner if (I == MCCVLineStartStop.end()) 283*b5258722SReid Kleckner return {~0ULL, 0}; 284*b5258722SReid Kleckner return I->second; 285*b5258722SReid Kleckner } 286*b5258722SReid Kleckner 287*b5258722SReid Kleckner ArrayRef<MCCVLineEntry> CodeViewContext::getLinesForExtent(size_t L, size_t R) { 288*b5258722SReid Kleckner if (R <= L) 289*b5258722SReid Kleckner return None; 290*b5258722SReid Kleckner if (L >= MCCVLines.size()) 291*b5258722SReid Kleckner return None; 292*b5258722SReid Kleckner return makeArrayRef(&MCCVLines[L], R - L); 293*b5258722SReid Kleckner } 294*b5258722SReid Kleckner 2952214ed89SReid Kleckner void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, 2962214ed89SReid Kleckner unsigned FuncId, 2972214ed89SReid Kleckner const MCSymbol *FuncBegin, 2982214ed89SReid Kleckner const MCSymbol *FuncEnd) { 2992214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 300a0b44ef6SDavid Blaikie MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin", false), 301a0b44ef6SDavid Blaikie *LineEnd = Ctx.createTempSymbol("linetable_end", false); 3022214ed89SReid Kleckner 3038c099fe0SZachary Turner OS.EmitIntValue(unsigned(DebugSubsectionKind::Lines), 4); 3042214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4); 3052214ed89SReid Kleckner OS.EmitLabel(LineBegin); 306f7d84ee6SKeno Fischer OS.EmitCOFFSecRel32(FuncBegin, /*Offset=*/0); 3072214ed89SReid Kleckner OS.EmitCOFFSectionIndex(FuncBegin); 3082214ed89SReid Kleckner 3092214ed89SReid Kleckner // Actual line info. 3106fcbd7e9SDavid Majnemer std::vector<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId); 3112214ed89SReid Kleckner bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) { 3122214ed89SReid Kleckner return LineEntry.getColumn() != 0; 3132214ed89SReid Kleckner }); 3145b6e4e0aSZachary Turner OS.EmitIntValue(HaveColumns ? int(LF_HaveColumns) : 0, 2); 3152214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4); 3162214ed89SReid Kleckner 3172214ed89SReid Kleckner for (auto I = Locs.begin(), E = Locs.end(); I != E;) { 3182214ed89SReid Kleckner // Emit a file segment for the run of locations that share a file id. 3192214ed89SReid Kleckner unsigned CurFileNum = I->getFileNum(); 3202214ed89SReid Kleckner auto FileSegEnd = 3212214ed89SReid Kleckner std::find_if(I, E, [CurFileNum](const MCCVLineEntry &Loc) { 3222214ed89SReid Kleckner return Loc.getFileNum() != CurFileNum; 3232214ed89SReid Kleckner }); 3242214ed89SReid Kleckner unsigned EntryCount = FileSegEnd - I; 32526fa1bf4SReid Kleckner OS.AddComment( 32626fa1bf4SReid Kleckner "Segment for file '" + 32726fa1bf4SReid Kleckner Twine(getStringTableFragment() 32826fa1bf4SReid Kleckner ->getContents()[Files[CurFileNum - 1].StringTableOffset]) + 3292214ed89SReid Kleckner "' begins"); 33026fa1bf4SReid Kleckner OS.EmitCVFileChecksumOffsetDirective(CurFileNum); 3312214ed89SReid Kleckner OS.EmitIntValue(EntryCount, 4); 3322214ed89SReid Kleckner uint32_t SegmentSize = 12; 3332214ed89SReid Kleckner SegmentSize += 8 * EntryCount; 3342214ed89SReid Kleckner if (HaveColumns) 3352214ed89SReid Kleckner SegmentSize += 4 * EntryCount; 3362214ed89SReid Kleckner OS.EmitIntValue(SegmentSize, 4); 3372214ed89SReid Kleckner 3382214ed89SReid Kleckner for (auto J = I; J != FileSegEnd; ++J) { 3392214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4); 3402214ed89SReid Kleckner unsigned LineData = J->getLine(); 3412214ed89SReid Kleckner if (J->isStmt()) 3426fcbd7e9SDavid Majnemer LineData |= LineInfo::StatementFlag; 3432214ed89SReid Kleckner OS.EmitIntValue(LineData, 4); 3442214ed89SReid Kleckner } 3452214ed89SReid Kleckner if (HaveColumns) { 3462214ed89SReid Kleckner for (auto J = I; J != FileSegEnd; ++J) { 3472214ed89SReid Kleckner OS.EmitIntValue(J->getColumn(), 2); 3482214ed89SReid Kleckner OS.EmitIntValue(0, 2); 3492214ed89SReid Kleckner } 3502214ed89SReid Kleckner } 3512214ed89SReid Kleckner I = FileSegEnd; 3522214ed89SReid Kleckner } 3532214ed89SReid Kleckner OS.EmitLabel(LineEnd); 3542214ed89SReid Kleckner } 3552214ed89SReid Kleckner 3566fcbd7e9SDavid Majnemer static bool compressAnnotation(uint32_t Data, SmallVectorImpl<char> &Buffer) { 3576fcbd7e9SDavid Majnemer if (isUInt<7>(Data)) { 3586fcbd7e9SDavid Majnemer Buffer.push_back(Data); 3596fcbd7e9SDavid Majnemer return true; 3606fcbd7e9SDavid Majnemer } 3616fcbd7e9SDavid Majnemer 3626fcbd7e9SDavid Majnemer if (isUInt<14>(Data)) { 3636fcbd7e9SDavid Majnemer Buffer.push_back((Data >> 8) | 0x80); 3646fcbd7e9SDavid Majnemer Buffer.push_back(Data & 0xff); 3656fcbd7e9SDavid Majnemer return true; 3666fcbd7e9SDavid Majnemer } 3676fcbd7e9SDavid Majnemer 3686fcbd7e9SDavid Majnemer if (isUInt<29>(Data)) { 3696fcbd7e9SDavid Majnemer Buffer.push_back((Data >> 24) | 0xC0); 3706fcbd7e9SDavid Majnemer Buffer.push_back((Data >> 16) & 0xff); 3716fcbd7e9SDavid Majnemer Buffer.push_back((Data >> 8) & 0xff); 3726fcbd7e9SDavid Majnemer Buffer.push_back(Data & 0xff); 3736fcbd7e9SDavid Majnemer return true; 3746fcbd7e9SDavid Majnemer } 3756fcbd7e9SDavid Majnemer 3766fcbd7e9SDavid Majnemer return false; 3776fcbd7e9SDavid Majnemer } 3786fcbd7e9SDavid Majnemer 37963a2846eSZachary Turner static bool compressAnnotation(BinaryAnnotationsOpCode Annotation, 38063a2846eSZachary Turner SmallVectorImpl<char> &Buffer) { 38163a2846eSZachary Turner return compressAnnotation(static_cast<uint32_t>(Annotation), Buffer); 38263a2846eSZachary Turner } 38363a2846eSZachary Turner 3846fcbd7e9SDavid Majnemer static uint32_t encodeSignedNumber(uint32_t Data) { 3856fcbd7e9SDavid Majnemer if (Data >> 31) 3866fcbd7e9SDavid Majnemer return ((-Data) << 1) | 1; 3876fcbd7e9SDavid Majnemer return Data << 1; 3886fcbd7e9SDavid Majnemer } 3896fcbd7e9SDavid Majnemer 390a9f4cc95SReid Kleckner void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS, 391a9f4cc95SReid Kleckner unsigned PrimaryFunctionId, 392a9f4cc95SReid Kleckner unsigned SourceFileId, 393a9f4cc95SReid Kleckner unsigned SourceLineNum, 394a9f4cc95SReid Kleckner const MCSymbol *FnStartSym, 395a9f4cc95SReid Kleckner const MCSymbol *FnEndSym) { 3961fcd610cSReid Kleckner // Create and insert a fragment into the current section that will be encoded 3971fcd610cSReid Kleckner // later. 398a9f4cc95SReid Kleckner new MCCVInlineLineTableFragment(PrimaryFunctionId, SourceFileId, 399a9f4cc95SReid Kleckner SourceLineNum, FnStartSym, FnEndSym, 400a9f4cc95SReid Kleckner OS.getCurrentSectionOnly()); 4016fcbd7e9SDavid Majnemer } 4026fcbd7e9SDavid Majnemer 403408b5e66SDavid Majnemer void CodeViewContext::emitDefRange( 404408b5e66SDavid Majnemer MCObjectStreamer &OS, 405408b5e66SDavid Majnemer ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, 406408b5e66SDavid Majnemer StringRef FixedSizePortion) { 407408b5e66SDavid Majnemer // Create and insert a fragment into the current section that will be encoded 408408b5e66SDavid Majnemer // later. 409408b5e66SDavid Majnemer new MCCVDefRangeFragment(Ranges, FixedSizePortion, 410408b5e66SDavid Majnemer OS.getCurrentSectionOnly()); 411408b5e66SDavid Majnemer } 412408b5e66SDavid Majnemer 413cb91e7d3SReid Kleckner static unsigned computeLabelDiff(MCAsmLayout &Layout, const MCSymbol *Begin, 4141fcd610cSReid Kleckner const MCSymbol *End) { 4151fcd610cSReid Kleckner MCContext &Ctx = Layout.getAssembler().getContext(); 4161fcd610cSReid Kleckner MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; 4171fcd610cSReid Kleckner const MCExpr *BeginRef = MCSymbolRefExpr::create(Begin, Variant, Ctx), 4181fcd610cSReid Kleckner *EndRef = MCSymbolRefExpr::create(End, Variant, Ctx); 4191fcd610cSReid Kleckner const MCExpr *AddrDelta = 4201fcd610cSReid Kleckner MCBinaryExpr::create(MCBinaryExpr::Sub, EndRef, BeginRef, Ctx); 4211fcd610cSReid Kleckner int64_t Result; 4221fcd610cSReid Kleckner bool Success = AddrDelta->evaluateKnownAbsolute(Result, Layout); 4231fcd610cSReid Kleckner assert(Success && "failed to evaluate label difference as absolute"); 4241fcd610cSReid Kleckner (void)Success; 4251fcd610cSReid Kleckner assert(Result >= 0 && "negative label difference requested"); 4261fcd610cSReid Kleckner assert(Result < UINT_MAX && "label difference greater than 2GB"); 4271fcd610cSReid Kleckner return unsigned(Result); 4281fcd610cSReid Kleckner } 4296fcbd7e9SDavid Majnemer 4301fcd610cSReid Kleckner void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, 4311fcd610cSReid Kleckner MCCVInlineLineTableFragment &Frag) { 4321fcd610cSReid Kleckner size_t LocBegin; 4331fcd610cSReid Kleckner size_t LocEnd; 4341fcd610cSReid Kleckner std::tie(LocBegin, LocEnd) = getLineExtent(Frag.SiteFuncId); 435a9f4cc95SReid Kleckner 436a9f4cc95SReid Kleckner // Include all child inline call sites in our .cv_loc extent. 437a9f4cc95SReid Kleckner MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId); 438a9f4cc95SReid Kleckner for (auto &KV : SiteInfo->InlinedAtMap) { 439a9f4cc95SReid Kleckner unsigned ChildId = KV.first; 440a9f4cc95SReid Kleckner auto Extent = getLineExtent(ChildId); 4411fcd610cSReid Kleckner LocBegin = std::min(LocBegin, Extent.first); 4421fcd610cSReid Kleckner LocEnd = std::max(LocEnd, Extent.second); 4431fcd610cSReid Kleckner } 444a9f4cc95SReid Kleckner 4451fcd610cSReid Kleckner if (LocBegin >= LocEnd) 4461fcd610cSReid Kleckner return; 447c9911f28SDavid Majnemer ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd); 4481fcd610cSReid Kleckner if (Locs.empty()) 4491fcd610cSReid Kleckner return; 4501fcd610cSReid Kleckner 4511fcd610cSReid Kleckner // Make an artificial start location using the function start and the inlinee 4521fcd610cSReid Kleckner // lines start location information. All deltas start relative to this 4531fcd610cSReid Kleckner // location. 4541fcd610cSReid Kleckner MCCVLineEntry StartLoc(Frag.getFnStartSym(), MCCVLoc(Locs.front())); 4551fcd610cSReid Kleckner StartLoc.setFileNum(Frag.StartFileId); 4561fcd610cSReid Kleckner StartLoc.setLine(Frag.StartLineNum); 457c29b4f07SReid Kleckner bool HaveOpenRange = false; 4581fcd610cSReid Kleckner 459a9f4cc95SReid Kleckner const MCSymbol *LastLabel = Frag.getFnStartSym(); 460a9f4cc95SReid Kleckner MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc; 461a9f4cc95SReid Kleckner LastSourceLoc.File = Frag.StartFileId; 462a9f4cc95SReid Kleckner LastSourceLoc.Line = Frag.StartLineNum; 463a9f4cc95SReid Kleckner 4641fcd610cSReid Kleckner SmallVectorImpl<char> &Buffer = Frag.getContents(); 4651fcd610cSReid Kleckner Buffer.clear(); // Clear old contents if we went through relaxation. 4661fcd610cSReid Kleckner for (const MCCVLineEntry &Loc : Locs) { 467bb96df60SReid Kleckner // Exit early if our line table would produce an oversized InlineSiteSym 468bb96df60SReid Kleckner // record. Account for the ChangeCodeLength annotation emitted after the 469bb96df60SReid Kleckner // loop ends. 47046225b19SZachary Turner constexpr uint32_t InlineSiteSize = 12; 47146225b19SZachary Turner constexpr uint32_t AnnotationSize = 8; 47246225b19SZachary Turner size_t MaxBufferSize = MaxRecordLength - InlineSiteSize - AnnotationSize; 473bb96df60SReid Kleckner if (Buffer.size() >= MaxBufferSize) 474bb96df60SReid Kleckner break; 475bb96df60SReid Kleckner 476a9f4cc95SReid Kleckner if (Loc.getFunctionId() == Frag.SiteFuncId) { 477a9f4cc95SReid Kleckner CurSourceLoc.File = Loc.getFileNum(); 478a9f4cc95SReid Kleckner CurSourceLoc.Line = Loc.getLine(); 479a9f4cc95SReid Kleckner } else { 480a9f4cc95SReid Kleckner auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId()); 481a9f4cc95SReid Kleckner if (I != SiteInfo->InlinedAtMap.end()) { 482a9f4cc95SReid Kleckner // This .cv_loc is from a child inline call site. Use the source 483a9f4cc95SReid Kleckner // location of the inlined call site instead of the .cv_loc directive 484a9f4cc95SReid Kleckner // source location. 485a9f4cc95SReid Kleckner CurSourceLoc = I->second; 486a9f4cc95SReid Kleckner } else { 4871fcd610cSReid Kleckner // We've hit a cv_loc not attributed to this inline call site. Use this 4881fcd610cSReid Kleckner // label to end the PC range. 489c29b4f07SReid Kleckner if (HaveOpenRange) { 490a9f4cc95SReid Kleckner unsigned Length = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); 49163a2846eSZachary Turner compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer); 4921fcd610cSReid Kleckner compressAnnotation(Length, Buffer); 493a9f4cc95SReid Kleckner LastLabel = Loc.getLabel(); 4941fcd610cSReid Kleckner } 495c29b4f07SReid Kleckner HaveOpenRange = false; 4961fcd610cSReid Kleckner continue; 4971fcd610cSReid Kleckner } 498a9f4cc95SReid Kleckner } 499c29b4f07SReid Kleckner 500a9f4cc95SReid Kleckner // Skip this .cv_loc if we have an open range and this isn't a meaningful 501a9f4cc95SReid Kleckner // source location update. The current table format does not support column 502a9f4cc95SReid Kleckner // info, so we can skip updates for those. 503a9f4cc95SReid Kleckner if (HaveOpenRange && CurSourceLoc.File == LastSourceLoc.File && 504a9f4cc95SReid Kleckner CurSourceLoc.Line == LastSourceLoc.Line) 505c29b4f07SReid Kleckner continue; 506a9f4cc95SReid Kleckner 507c29b4f07SReid Kleckner HaveOpenRange = true; 5081fcd610cSReid Kleckner 509a9f4cc95SReid Kleckner if (CurSourceLoc.File != LastSourceLoc.File) { 51026fa1bf4SReid Kleckner unsigned FileOffset = static_cast<const MCConstantExpr *>( 51126fa1bf4SReid Kleckner Files[CurSourceLoc.File - 1] 51226fa1bf4SReid Kleckner .ChecksumTableOffset->getVariableValue()) 51326fa1bf4SReid Kleckner ->getValue(); 51463a2846eSZachary Turner compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer); 515344078f5SReid Kleckner compressAnnotation(FileOffset, Buffer); 5161fcd610cSReid Kleckner } 5171fcd610cSReid Kleckner 518a9f4cc95SReid Kleckner int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line; 5191fcd610cSReid Kleckner unsigned EncodedLineDelta = encodeSignedNumber(LineDelta); 520a9f4cc95SReid Kleckner unsigned CodeDelta = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); 521a9f4cc95SReid Kleckner if (CodeDelta == 0 && LineDelta != 0) { 52263a2846eSZachary Turner compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer); 5231fcd610cSReid Kleckner compressAnnotation(EncodedLineDelta, Buffer); 5241fcd610cSReid Kleckner } else if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) { 5251fcd610cSReid Kleckner // The ChangeCodeOffsetAndLineOffset combination opcode is used when the 5261fcd610cSReid Kleckner // encoded line delta uses 3 or fewer set bits and the code offset fits 5271fcd610cSReid Kleckner // in one nibble. 5281fcd610cSReid Kleckner unsigned Operand = (EncodedLineDelta << 4) | CodeDelta; 52963a2846eSZachary Turner compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset, 53063a2846eSZachary Turner Buffer); 5311fcd610cSReid Kleckner compressAnnotation(Operand, Buffer); 5321fcd610cSReid Kleckner } else { 5331fcd610cSReid Kleckner // Otherwise use the separate line and code deltas. 534a9f4cc95SReid Kleckner if (LineDelta != 0) { 53563a2846eSZachary Turner compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer); 5361fcd610cSReid Kleckner compressAnnotation(EncodedLineDelta, Buffer); 537a9f4cc95SReid Kleckner } 53863a2846eSZachary Turner compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffset, Buffer); 5391fcd610cSReid Kleckner compressAnnotation(CodeDelta, Buffer); 5401fcd610cSReid Kleckner } 5416fcbd7e9SDavid Majnemer 542a9f4cc95SReid Kleckner LastLabel = Loc.getLabel(); 543a9f4cc95SReid Kleckner LastSourceLoc = CurSourceLoc; 5446fcbd7e9SDavid Majnemer } 545c9911f28SDavid Majnemer 546c29b4f07SReid Kleckner assert(HaveOpenRange); 547c9911f28SDavid Majnemer 548c9911f28SDavid Majnemer unsigned EndSymLength = 549a9f4cc95SReid Kleckner computeLabelDiff(Layout, LastLabel, Frag.getFnEndSym()); 550c9911f28SDavid Majnemer unsigned LocAfterLength = ~0U; 551c9911f28SDavid Majnemer ArrayRef<MCCVLineEntry> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1); 552cb91e7d3SReid Kleckner if (!LocAfter.empty()) { 553cb91e7d3SReid Kleckner // Only try to compute this difference if we're in the same section. 554cb91e7d3SReid Kleckner const MCCVLineEntry &Loc = LocAfter[0]; 5555e102eeeSSam Clegg if (&Loc.getLabel()->getSection() == &LastLabel->getSection()) 556a9f4cc95SReid Kleckner LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); 557cb91e7d3SReid Kleckner } 558c9911f28SDavid Majnemer 55963a2846eSZachary Turner compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer); 560c9911f28SDavid Majnemer compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer); 5616fcbd7e9SDavid Majnemer } 5626fcbd7e9SDavid Majnemer 563408b5e66SDavid Majnemer void CodeViewContext::encodeDefRange(MCAsmLayout &Layout, 564408b5e66SDavid Majnemer MCCVDefRangeFragment &Frag) { 565408b5e66SDavid Majnemer MCContext &Ctx = Layout.getAssembler().getContext(); 566408b5e66SDavid Majnemer SmallVectorImpl<char> &Contents = Frag.getContents(); 567408b5e66SDavid Majnemer Contents.clear(); 568408b5e66SDavid Majnemer SmallVectorImpl<MCFixup> &Fixups = Frag.getFixups(); 569408b5e66SDavid Majnemer Fixups.clear(); 570408b5e66SDavid Majnemer raw_svector_ostream OS(Contents); 571408b5e66SDavid Majnemer 572be82d3ecSReid Kleckner // Compute all the sizes up front. 573be82d3ecSReid Kleckner SmallVector<std::pair<unsigned, unsigned>, 4> GapAndRangeSizes; 574be82d3ecSReid Kleckner const MCSymbol *LastLabel = nullptr; 575408b5e66SDavid Majnemer for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) { 576be82d3ecSReid Kleckner unsigned GapSize = 577be82d3ecSReid Kleckner LastLabel ? computeLabelDiff(Layout, LastLabel, Range.first) : 0; 578408b5e66SDavid Majnemer unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second); 579be82d3ecSReid Kleckner GapAndRangeSizes.push_back({GapSize, RangeSize}); 580be82d3ecSReid Kleckner LastLabel = Range.second; 581be82d3ecSReid Kleckner } 582be82d3ecSReid Kleckner 583be82d3ecSReid Kleckner // Write down each range where the variable is defined. 584be82d3ecSReid Kleckner for (size_t I = 0, E = Frag.getRanges().size(); I != E;) { 585be82d3ecSReid Kleckner // If the range size of multiple consecutive ranges is under the max, 586be82d3ecSReid Kleckner // combine the ranges and emit some gaps. 587be82d3ecSReid Kleckner const MCSymbol *RangeBegin = Frag.getRanges()[I].first; 588be82d3ecSReid Kleckner unsigned RangeSize = GapAndRangeSizes[I].second; 589be82d3ecSReid Kleckner size_t J = I + 1; 590be82d3ecSReid Kleckner for (; J != E; ++J) { 591be82d3ecSReid Kleckner unsigned GapAndRangeSize = GapAndRangeSizes[J].first + GapAndRangeSizes[J].second; 592be82d3ecSReid Kleckner if (RangeSize + GapAndRangeSize > MaxDefRange) 593be82d3ecSReid Kleckner break; 594be82d3ecSReid Kleckner RangeSize += GapAndRangeSize; 595be82d3ecSReid Kleckner } 596be82d3ecSReid Kleckner unsigned NumGaps = J - I - 1; 597be82d3ecSReid Kleckner 598be82d3ecSReid Kleckner support::endian::Writer<support::little> LEWriter(OS); 599be82d3ecSReid Kleckner 600408b5e66SDavid Majnemer unsigned Bias = 0; 601408b5e66SDavid Majnemer // We must split the range into chunks of MaxDefRange, this is a fundamental 602408b5e66SDavid Majnemer // limitation of the file format. 603408b5e66SDavid Majnemer do { 604408b5e66SDavid Majnemer uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize); 605408b5e66SDavid Majnemer 606be82d3ecSReid Kleckner const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(RangeBegin, Ctx); 607408b5e66SDavid Majnemer const MCBinaryExpr *BE = 608408b5e66SDavid Majnemer MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx); 609408b5e66SDavid Majnemer MCValue Res; 610408b5e66SDavid Majnemer BE->evaluateAsRelocatable(Res, &Layout, /*Fixup=*/nullptr); 611408b5e66SDavid Majnemer 612408b5e66SDavid Majnemer // Each record begins with a 2-byte number indicating how large the record 613408b5e66SDavid Majnemer // is. 614408b5e66SDavid Majnemer StringRef FixedSizePortion = Frag.getFixedSizePortion(); 615408b5e66SDavid Majnemer // Our record is a fixed sized prefix and a LocalVariableAddrRange that we 616408b5e66SDavid Majnemer // are artificially constructing. 617be82d3ecSReid Kleckner size_t RecordSize = FixedSizePortion.size() + 618be82d3ecSReid Kleckner sizeof(LocalVariableAddrRange) + 4 * NumGaps; 61911cf053bSReid Kleckner // Write out the record size. 62011cf053bSReid Kleckner LEWriter.write<uint16_t>(RecordSize); 621408b5e66SDavid Majnemer // Write out the fixed size prefix. 622408b5e66SDavid Majnemer OS << FixedSizePortion; 623408b5e66SDavid Majnemer // Make space for a fixup that will eventually have a section relative 624408b5e66SDavid Majnemer // relocation pointing at the offset where the variable becomes live. 625408b5e66SDavid Majnemer Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4)); 62611cf053bSReid Kleckner LEWriter.write<uint32_t>(0); // Fixup for code start. 627408b5e66SDavid Majnemer // Make space for a fixup that will record the section index for the code. 628408b5e66SDavid Majnemer Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2)); 62911cf053bSReid Kleckner LEWriter.write<uint16_t>(0); // Fixup for section index. 630408b5e66SDavid Majnemer // Write down the range's extent. 631be82d3ecSReid Kleckner LEWriter.write<uint16_t>(Chunk); 632408b5e66SDavid Majnemer 633408b5e66SDavid Majnemer // Move on to the next range. 634408b5e66SDavid Majnemer Bias += Chunk; 635408b5e66SDavid Majnemer RangeSize -= Chunk; 636408b5e66SDavid Majnemer } while (RangeSize > 0); 637be82d3ecSReid Kleckner 638be82d3ecSReid Kleckner // Emit the gaps afterwards. 63911cf053bSReid Kleckner assert((NumGaps == 0 || Bias <= MaxDefRange) && 640be82d3ecSReid Kleckner "large ranges should not have gaps"); 641be82d3ecSReid Kleckner unsigned GapStartOffset = GapAndRangeSizes[I].second; 642be82d3ecSReid Kleckner for (++I; I != J; ++I) { 643be82d3ecSReid Kleckner unsigned GapSize, RangeSize; 644be82d3ecSReid Kleckner assert(I < GapAndRangeSizes.size()); 645be82d3ecSReid Kleckner std::tie(GapSize, RangeSize) = GapAndRangeSizes[I]; 646be82d3ecSReid Kleckner LEWriter.write<uint16_t>(GapStartOffset); 64711cf053bSReid Kleckner LEWriter.write<uint16_t>(GapSize); 648be82d3ecSReid Kleckner GapStartOffset += GapSize + RangeSize; 649be82d3ecSReid Kleckner } 650408b5e66SDavid Majnemer } 651408b5e66SDavid Majnemer } 652408b5e66SDavid Majnemer 6532214ed89SReid Kleckner // 6542214ed89SReid Kleckner // This is called when an instruction is assembled into the specified section 6552214ed89SReid Kleckner // and if there is information from the last .cv_loc directive that has yet to have 6562214ed89SReid Kleckner // a line entry made for it is made. 6572214ed89SReid Kleckner // 6582214ed89SReid Kleckner void MCCVLineEntry::Make(MCObjectStreamer *MCOS) { 659a5b1eef8SReid Kleckner CodeViewContext &CVC = MCOS->getContext().getCVContext(); 660a5b1eef8SReid Kleckner if (!CVC.getCVLocSeen()) 6612214ed89SReid Kleckner return; 6622214ed89SReid Kleckner 6632214ed89SReid Kleckner // Create a symbol at in the current section for use in the line entry. 6642214ed89SReid Kleckner MCSymbol *LineSym = MCOS->getContext().createTempSymbol(); 6652214ed89SReid Kleckner // Set the value of the symbol to use for the MCCVLineEntry. 6662214ed89SReid Kleckner MCOS->EmitLabel(LineSym); 6672214ed89SReid Kleckner 6682214ed89SReid Kleckner // Get the current .loc info saved in the context. 669a5b1eef8SReid Kleckner const MCCVLoc &CVLoc = CVC.getCurrentCVLoc(); 6702214ed89SReid Kleckner 6712214ed89SReid Kleckner // Create a (local) line entry with the symbol and the current .loc info. 6722214ed89SReid Kleckner MCCVLineEntry LineEntry(LineSym, CVLoc); 6732214ed89SReid Kleckner 6742214ed89SReid Kleckner // clear CVLocSeen saying the current .loc info is now used. 675a5b1eef8SReid Kleckner CVC.clearCVLocSeen(); 6762214ed89SReid Kleckner 6772214ed89SReid Kleckner // Add the line entry to this section's entries. 678a5b1eef8SReid Kleckner CVC.addLineEntry(LineEntry); 6792214ed89SReid Kleckner } 680