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" 162214ed89SReid Kleckner #include "llvm/DebugInfo/CodeView/CodeView.h" 172214ed89SReid Kleckner #include "llvm/DebugInfo/CodeView/Line.h" 182214ed89SReid Kleckner #include "llvm/MC/MCContext.h" 192214ed89SReid Kleckner #include "llvm/MC/MCObjectStreamer.h" 202214ed89SReid Kleckner #include "llvm/Support/COFF.h" 212214ed89SReid Kleckner 222214ed89SReid Kleckner using namespace llvm; 232214ed89SReid Kleckner using namespace llvm::codeview; 242214ed89SReid Kleckner 252214ed89SReid Kleckner CodeViewContext::CodeViewContext() {} 262214ed89SReid Kleckner 272214ed89SReid Kleckner CodeViewContext::~CodeViewContext() { 282214ed89SReid Kleckner // If someone inserted strings into the string table but never actually 292214ed89SReid Kleckner // emitted them somewhere, clean up the fragment. 302214ed89SReid Kleckner if (!InsertedStrTabFragment) 312214ed89SReid Kleckner delete StrTabFragment; 322214ed89SReid Kleckner } 332214ed89SReid Kleckner 342214ed89SReid Kleckner /// This is a valid number for use with .cv_loc if we've already seen a .cv_file 352214ed89SReid Kleckner /// for it. 362214ed89SReid Kleckner bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const { 372214ed89SReid Kleckner unsigned Idx = FileNumber - 1; 382214ed89SReid Kleckner if (Idx < Filenames.size()) 392214ed89SReid Kleckner return !Filenames[Idx].empty(); 402214ed89SReid Kleckner return false; 412214ed89SReid Kleckner } 422214ed89SReid Kleckner 432214ed89SReid Kleckner bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) { 442214ed89SReid Kleckner assert(FileNumber > 0); 452214ed89SReid Kleckner Filename = addToStringTable(Filename); 462214ed89SReid Kleckner unsigned Idx = FileNumber - 1; 472214ed89SReid Kleckner if (Idx >= Filenames.size()) 482214ed89SReid Kleckner Filenames.resize(Idx + 1); 492214ed89SReid Kleckner 502214ed89SReid Kleckner if (Filename.empty()) 512214ed89SReid Kleckner Filename = "<stdin>"; 522214ed89SReid Kleckner 532214ed89SReid Kleckner if (!Filenames[Idx].empty()) 542214ed89SReid Kleckner return false; 552214ed89SReid Kleckner 562214ed89SReid Kleckner // FIXME: We should store the string table offset of the filename, rather than 572214ed89SReid Kleckner // the filename itself for efficiency. 582214ed89SReid Kleckner Filename = addToStringTable(Filename); 592214ed89SReid Kleckner 602214ed89SReid Kleckner Filenames[Idx] = Filename; 612214ed89SReid Kleckner return true; 622214ed89SReid Kleckner } 632214ed89SReid Kleckner 642214ed89SReid Kleckner MCDataFragment *CodeViewContext::getStringTableFragment() { 652214ed89SReid Kleckner if (!StrTabFragment) { 662214ed89SReid Kleckner StrTabFragment = new MCDataFragment(); 672214ed89SReid Kleckner // Start a new string table out with a null byte. 682214ed89SReid Kleckner StrTabFragment->getContents().push_back('\0'); 692214ed89SReid Kleckner } 702214ed89SReid Kleckner return StrTabFragment; 712214ed89SReid Kleckner } 722214ed89SReid Kleckner 732214ed89SReid Kleckner StringRef CodeViewContext::addToStringTable(StringRef S) { 742214ed89SReid Kleckner SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents(); 752214ed89SReid Kleckner auto Insertion = 762214ed89SReid Kleckner StringTable.insert(std::make_pair(S, unsigned(Contents.size()))); 772214ed89SReid Kleckner // Return the string from the table, since it is stable. 782214ed89SReid Kleckner S = Insertion.first->first(); 792214ed89SReid Kleckner if (Insertion.second) { 802214ed89SReid Kleckner // The string map key is always null terminated. 812214ed89SReid Kleckner Contents.append(S.begin(), S.end() + 1); 822214ed89SReid Kleckner } 832214ed89SReid Kleckner return S; 842214ed89SReid Kleckner } 852214ed89SReid Kleckner 862214ed89SReid Kleckner unsigned CodeViewContext::getStringTableOffset(StringRef S) { 872214ed89SReid Kleckner // A string table offset of zero is always the empty string. 882214ed89SReid Kleckner if (S.empty()) 892214ed89SReid Kleckner return 0; 902214ed89SReid Kleckner auto I = StringTable.find(S); 912214ed89SReid Kleckner assert(I != StringTable.end()); 922214ed89SReid Kleckner return I->second; 932214ed89SReid Kleckner } 942214ed89SReid Kleckner 952214ed89SReid Kleckner void CodeViewContext::emitStringTable(MCObjectStreamer &OS) { 962214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 97*a0b44ef6SDavid Blaikie MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin", false), 98*a0b44ef6SDavid Blaikie *StringEnd = Ctx.createTempSymbol("strtab_end", false); 992214ed89SReid Kleckner 1002214ed89SReid Kleckner OS.EmitIntValue(unsigned(ModuleSubstreamKind::StringTable), 4); 1012214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4); 1022214ed89SReid Kleckner OS.EmitLabel(StringBegin); 1032214ed89SReid Kleckner 1042214ed89SReid Kleckner // Put the string table data fragment here, if we haven't already put it 1052214ed89SReid Kleckner // somewhere else. If somebody wants two string tables in their .s file, one 1062214ed89SReid Kleckner // will just be empty. 1072214ed89SReid Kleckner if (!InsertedStrTabFragment) { 1082214ed89SReid Kleckner OS.insert(getStringTableFragment()); 1092214ed89SReid Kleckner InsertedStrTabFragment = true; 1102214ed89SReid Kleckner } 1112214ed89SReid Kleckner 1122214ed89SReid Kleckner OS.EmitValueToAlignment(4, 0); 1132214ed89SReid Kleckner 1142214ed89SReid Kleckner OS.EmitLabel(StringEnd); 1152214ed89SReid Kleckner } 1162214ed89SReid Kleckner 1172214ed89SReid Kleckner void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) { 1182214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 119*a0b44ef6SDavid Blaikie MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin", false), 120*a0b44ef6SDavid Blaikie *FileEnd = Ctx.createTempSymbol("filechecksums_end", false); 1212214ed89SReid Kleckner 1222214ed89SReid Kleckner OS.EmitIntValue(unsigned(ModuleSubstreamKind::FileChecksums), 4); 1232214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4); 1242214ed89SReid Kleckner OS.EmitLabel(FileBegin); 1252214ed89SReid Kleckner 1262214ed89SReid Kleckner // Emit an array of FileChecksum entries. We index into this table using the 1272214ed89SReid Kleckner // user-provided file number. Each entry is currently 8 bytes, as we don't 1282214ed89SReid Kleckner // emit checksums. 1292214ed89SReid Kleckner for (StringRef Filename : Filenames) { 1302214ed89SReid Kleckner OS.EmitIntValue(getStringTableOffset(Filename), 4); 1312214ed89SReid Kleckner // Zero the next two fields and align back to 4 bytes. This indicates that 1322214ed89SReid Kleckner // no checksum is present. 1332214ed89SReid Kleckner OS.EmitIntValue(0, 4); 1342214ed89SReid Kleckner } 1352214ed89SReid Kleckner 1362214ed89SReid Kleckner OS.EmitLabel(FileEnd); 1372214ed89SReid Kleckner } 1382214ed89SReid Kleckner 1392214ed89SReid Kleckner void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, 1402214ed89SReid Kleckner unsigned FuncId, 1412214ed89SReid Kleckner const MCSymbol *FuncBegin, 1422214ed89SReid Kleckner const MCSymbol *FuncEnd) { 1432214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 144*a0b44ef6SDavid Blaikie MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin", false), 145*a0b44ef6SDavid Blaikie *LineEnd = Ctx.createTempSymbol("linetable_end", false); 1462214ed89SReid Kleckner 1472214ed89SReid Kleckner OS.EmitIntValue(unsigned(ModuleSubstreamKind::Lines), 4); 1482214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4); 1492214ed89SReid Kleckner OS.EmitLabel(LineBegin); 1502214ed89SReid Kleckner OS.EmitCOFFSecRel32(FuncBegin); 1512214ed89SReid Kleckner OS.EmitCOFFSectionIndex(FuncBegin); 1522214ed89SReid Kleckner 1532214ed89SReid Kleckner // Actual line info. 1542214ed89SReid Kleckner ArrayRef<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId); 1552214ed89SReid Kleckner bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) { 1562214ed89SReid Kleckner return LineEntry.getColumn() != 0; 1572214ed89SReid Kleckner }); 1582214ed89SReid Kleckner OS.EmitIntValue(HaveColumns ? int(codeview::LineFlags::HaveColumns) : 0, 2); 1592214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4); 1602214ed89SReid Kleckner 1612214ed89SReid Kleckner for (auto I = Locs.begin(), E = Locs.end(); I != E;) { 1622214ed89SReid Kleckner // Emit a file segment for the run of locations that share a file id. 1632214ed89SReid Kleckner unsigned CurFileNum = I->getFileNum(); 1642214ed89SReid Kleckner auto FileSegEnd = 1652214ed89SReid Kleckner std::find_if(I, E, [CurFileNum](const MCCVLineEntry &Loc) { 1662214ed89SReid Kleckner return Loc.getFileNum() != CurFileNum; 1672214ed89SReid Kleckner }); 1682214ed89SReid Kleckner unsigned EntryCount = FileSegEnd - I; 1692214ed89SReid Kleckner OS.AddComment("Segment for file '" + Twine(Filenames[CurFileNum - 1]) + 1702214ed89SReid Kleckner "' begins"); 1712214ed89SReid Kleckner OS.EmitIntValue(8 * (CurFileNum - 1), 4); 1722214ed89SReid Kleckner OS.EmitIntValue(EntryCount, 4); 1732214ed89SReid Kleckner uint32_t SegmentSize = 12; 1742214ed89SReid Kleckner SegmentSize += 8 * EntryCount; 1752214ed89SReid Kleckner if (HaveColumns) 1762214ed89SReid Kleckner SegmentSize += 4 * EntryCount; 1772214ed89SReid Kleckner OS.EmitIntValue(SegmentSize, 4); 1782214ed89SReid Kleckner 1792214ed89SReid Kleckner for (auto J = I; J != FileSegEnd; ++J) { 1802214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4); 1812214ed89SReid Kleckner unsigned LineData = J->getLine(); 1822214ed89SReid Kleckner if (J->isStmt()) 1832214ed89SReid Kleckner LineData |= codeview::LineInfo::StatementFlag; 1842214ed89SReid Kleckner OS.EmitIntValue(LineData, 4); 1852214ed89SReid Kleckner } 1862214ed89SReid Kleckner if (HaveColumns) { 1872214ed89SReid Kleckner for (auto J = I; J != FileSegEnd; ++J) { 1882214ed89SReid Kleckner OS.EmitIntValue(J->getColumn(), 2); 1892214ed89SReid Kleckner OS.EmitIntValue(0, 2); 1902214ed89SReid Kleckner } 1912214ed89SReid Kleckner } 1922214ed89SReid Kleckner I = FileSegEnd; 1932214ed89SReid Kleckner } 1942214ed89SReid Kleckner OS.EmitLabel(LineEnd); 1952214ed89SReid Kleckner } 1962214ed89SReid Kleckner 1972214ed89SReid Kleckner // 1982214ed89SReid Kleckner // This is called when an instruction is assembled into the specified section 1992214ed89SReid Kleckner // and if there is information from the last .cv_loc directive that has yet to have 2002214ed89SReid Kleckner // a line entry made for it is made. 2012214ed89SReid Kleckner // 2022214ed89SReid Kleckner void MCCVLineEntry::Make(MCObjectStreamer *MCOS) { 2032214ed89SReid Kleckner if (!MCOS->getContext().getCVLocSeen()) 2042214ed89SReid Kleckner return; 2052214ed89SReid Kleckner 2062214ed89SReid Kleckner // Create a symbol at in the current section for use in the line entry. 2072214ed89SReid Kleckner MCSymbol *LineSym = MCOS->getContext().createTempSymbol(); 2082214ed89SReid Kleckner // Set the value of the symbol to use for the MCCVLineEntry. 2092214ed89SReid Kleckner MCOS->EmitLabel(LineSym); 2102214ed89SReid Kleckner 2112214ed89SReid Kleckner // Get the current .loc info saved in the context. 2122214ed89SReid Kleckner const MCCVLoc &CVLoc = MCOS->getContext().getCurrentCVLoc(); 2132214ed89SReid Kleckner 2142214ed89SReid Kleckner // Create a (local) line entry with the symbol and the current .loc info. 2152214ed89SReid Kleckner MCCVLineEntry LineEntry(LineSym, CVLoc); 2162214ed89SReid Kleckner 2172214ed89SReid Kleckner // clear CVLocSeen saying the current .loc info is now used. 2182214ed89SReid Kleckner MCOS->getContext().clearCVLocSeen(); 2192214ed89SReid Kleckner 2202214ed89SReid Kleckner // Add the line entry to this section's entries. 2212214ed89SReid Kleckner MCOS->getContext().getCVContext().addLineEntry(LineEntry); 2222214ed89SReid Kleckner } 223