1*2214ed89SReid Kleckner //===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===// 2*2214ed89SReid Kleckner // 3*2214ed89SReid Kleckner // The LLVM Compiler Infrastructure 4*2214ed89SReid Kleckner // 5*2214ed89SReid Kleckner // This file is distributed under the University of Illinois Open Source 6*2214ed89SReid Kleckner // License. See LICENSE.TXT for details. 7*2214ed89SReid Kleckner // 8*2214ed89SReid Kleckner //===----------------------------------------------------------------------===// 9*2214ed89SReid Kleckner // 10*2214ed89SReid Kleckner // Holds state from .cv_file and .cv_loc directives for later emission. 11*2214ed89SReid Kleckner // 12*2214ed89SReid Kleckner //===----------------------------------------------------------------------===// 13*2214ed89SReid Kleckner 14*2214ed89SReid Kleckner #include "llvm/MC/MCCodeView.h" 15*2214ed89SReid Kleckner #include "llvm/ADT/STLExtras.h" 16*2214ed89SReid Kleckner #include "llvm/DebugInfo/CodeView/CodeView.h" 17*2214ed89SReid Kleckner #include "llvm/DebugInfo/CodeView/Line.h" 18*2214ed89SReid Kleckner #include "llvm/MC/MCContext.h" 19*2214ed89SReid Kleckner #include "llvm/MC/MCObjectStreamer.h" 20*2214ed89SReid Kleckner #include "llvm/Support/COFF.h" 21*2214ed89SReid Kleckner 22*2214ed89SReid Kleckner using namespace llvm; 23*2214ed89SReid Kleckner using namespace llvm::codeview; 24*2214ed89SReid Kleckner 25*2214ed89SReid Kleckner CodeViewContext::CodeViewContext() {} 26*2214ed89SReid Kleckner 27*2214ed89SReid Kleckner CodeViewContext::~CodeViewContext() { 28*2214ed89SReid Kleckner // If someone inserted strings into the string table but never actually 29*2214ed89SReid Kleckner // emitted them somewhere, clean up the fragment. 30*2214ed89SReid Kleckner if (!InsertedStrTabFragment) 31*2214ed89SReid Kleckner delete StrTabFragment; 32*2214ed89SReid Kleckner } 33*2214ed89SReid Kleckner 34*2214ed89SReid Kleckner /// This is a valid number for use with .cv_loc if we've already seen a .cv_file 35*2214ed89SReid Kleckner /// for it. 36*2214ed89SReid Kleckner bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const { 37*2214ed89SReid Kleckner unsigned Idx = FileNumber - 1; 38*2214ed89SReid Kleckner if (Idx < Filenames.size()) 39*2214ed89SReid Kleckner return !Filenames[Idx].empty(); 40*2214ed89SReid Kleckner return false; 41*2214ed89SReid Kleckner } 42*2214ed89SReid Kleckner 43*2214ed89SReid Kleckner bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) { 44*2214ed89SReid Kleckner assert(FileNumber > 0); 45*2214ed89SReid Kleckner Filename = addToStringTable(Filename); 46*2214ed89SReid Kleckner unsigned Idx = FileNumber - 1; 47*2214ed89SReid Kleckner if (Idx >= Filenames.size()) 48*2214ed89SReid Kleckner Filenames.resize(Idx + 1); 49*2214ed89SReid Kleckner 50*2214ed89SReid Kleckner if (Filename.empty()) 51*2214ed89SReid Kleckner Filename = "<stdin>"; 52*2214ed89SReid Kleckner 53*2214ed89SReid Kleckner if (!Filenames[Idx].empty()) 54*2214ed89SReid Kleckner return false; 55*2214ed89SReid Kleckner 56*2214ed89SReid Kleckner // FIXME: We should store the string table offset of the filename, rather than 57*2214ed89SReid Kleckner // the filename itself for efficiency. 58*2214ed89SReid Kleckner Filename = addToStringTable(Filename); 59*2214ed89SReid Kleckner 60*2214ed89SReid Kleckner Filenames[Idx] = Filename; 61*2214ed89SReid Kleckner return true; 62*2214ed89SReid Kleckner } 63*2214ed89SReid Kleckner 64*2214ed89SReid Kleckner MCDataFragment *CodeViewContext::getStringTableFragment() { 65*2214ed89SReid Kleckner if (!StrTabFragment) { 66*2214ed89SReid Kleckner StrTabFragment = new MCDataFragment(); 67*2214ed89SReid Kleckner // Start a new string table out with a null byte. 68*2214ed89SReid Kleckner StrTabFragment->getContents().push_back('\0'); 69*2214ed89SReid Kleckner } 70*2214ed89SReid Kleckner return StrTabFragment; 71*2214ed89SReid Kleckner } 72*2214ed89SReid Kleckner 73*2214ed89SReid Kleckner StringRef CodeViewContext::addToStringTable(StringRef S) { 74*2214ed89SReid Kleckner SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents(); 75*2214ed89SReid Kleckner auto Insertion = 76*2214ed89SReid Kleckner StringTable.insert(std::make_pair(S, unsigned(Contents.size()))); 77*2214ed89SReid Kleckner // Return the string from the table, since it is stable. 78*2214ed89SReid Kleckner S = Insertion.first->first(); 79*2214ed89SReid Kleckner if (Insertion.second) { 80*2214ed89SReid Kleckner // The string map key is always null terminated. 81*2214ed89SReid Kleckner Contents.append(S.begin(), S.end() + 1); 82*2214ed89SReid Kleckner } 83*2214ed89SReid Kleckner return S; 84*2214ed89SReid Kleckner } 85*2214ed89SReid Kleckner 86*2214ed89SReid Kleckner unsigned CodeViewContext::getStringTableOffset(StringRef S) { 87*2214ed89SReid Kleckner // A string table offset of zero is always the empty string. 88*2214ed89SReid Kleckner if (S.empty()) 89*2214ed89SReid Kleckner return 0; 90*2214ed89SReid Kleckner auto I = StringTable.find(S); 91*2214ed89SReid Kleckner assert(I != StringTable.end()); 92*2214ed89SReid Kleckner return I->second; 93*2214ed89SReid Kleckner } 94*2214ed89SReid Kleckner 95*2214ed89SReid Kleckner void CodeViewContext::emitStringTable(MCObjectStreamer &OS) { 96*2214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 97*2214ed89SReid Kleckner MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin"), 98*2214ed89SReid Kleckner *StringEnd = Ctx.createTempSymbol("strtab_end"); 99*2214ed89SReid Kleckner 100*2214ed89SReid Kleckner OS.EmitIntValue(unsigned(ModuleSubstreamKind::StringTable), 4); 101*2214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4); 102*2214ed89SReid Kleckner OS.EmitLabel(StringBegin); 103*2214ed89SReid Kleckner 104*2214ed89SReid Kleckner // Put the string table data fragment here, if we haven't already put it 105*2214ed89SReid Kleckner // somewhere else. If somebody wants two string tables in their .s file, one 106*2214ed89SReid Kleckner // will just be empty. 107*2214ed89SReid Kleckner if (!InsertedStrTabFragment) { 108*2214ed89SReid Kleckner OS.insert(getStringTableFragment()); 109*2214ed89SReid Kleckner InsertedStrTabFragment = true; 110*2214ed89SReid Kleckner } 111*2214ed89SReid Kleckner 112*2214ed89SReid Kleckner OS.EmitValueToAlignment(4, 0); 113*2214ed89SReid Kleckner 114*2214ed89SReid Kleckner OS.EmitLabel(StringEnd); 115*2214ed89SReid Kleckner } 116*2214ed89SReid Kleckner 117*2214ed89SReid Kleckner void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) { 118*2214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 119*2214ed89SReid Kleckner MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin"), 120*2214ed89SReid Kleckner *FileEnd = Ctx.createTempSymbol("filechecksums_end"); 121*2214ed89SReid Kleckner 122*2214ed89SReid Kleckner OS.EmitIntValue(unsigned(ModuleSubstreamKind::FileChecksums), 4); 123*2214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4); 124*2214ed89SReid Kleckner OS.EmitLabel(FileBegin); 125*2214ed89SReid Kleckner 126*2214ed89SReid Kleckner // Emit an array of FileChecksum entries. We index into this table using the 127*2214ed89SReid Kleckner // user-provided file number. Each entry is currently 8 bytes, as we don't 128*2214ed89SReid Kleckner // emit checksums. 129*2214ed89SReid Kleckner for (StringRef Filename : Filenames) { 130*2214ed89SReid Kleckner OS.EmitIntValue(getStringTableOffset(Filename), 4); 131*2214ed89SReid Kleckner // Zero the next two fields and align back to 4 bytes. This indicates that 132*2214ed89SReid Kleckner // no checksum is present. 133*2214ed89SReid Kleckner OS.EmitIntValue(0, 4); 134*2214ed89SReid Kleckner } 135*2214ed89SReid Kleckner 136*2214ed89SReid Kleckner OS.EmitLabel(FileEnd); 137*2214ed89SReid Kleckner } 138*2214ed89SReid Kleckner 139*2214ed89SReid Kleckner void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, 140*2214ed89SReid Kleckner unsigned FuncId, 141*2214ed89SReid Kleckner const MCSymbol *FuncBegin, 142*2214ed89SReid Kleckner const MCSymbol *FuncEnd) { 143*2214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 144*2214ed89SReid Kleckner MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin"), 145*2214ed89SReid Kleckner *LineEnd = Ctx.createTempSymbol("linetable_end"); 146*2214ed89SReid Kleckner 147*2214ed89SReid Kleckner OS.EmitIntValue(unsigned(ModuleSubstreamKind::Lines), 4); 148*2214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4); 149*2214ed89SReid Kleckner OS.EmitLabel(LineBegin); 150*2214ed89SReid Kleckner OS.EmitCOFFSecRel32(FuncBegin); 151*2214ed89SReid Kleckner OS.EmitCOFFSectionIndex(FuncBegin); 152*2214ed89SReid Kleckner 153*2214ed89SReid Kleckner // Actual line info. 154*2214ed89SReid Kleckner ArrayRef<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId); 155*2214ed89SReid Kleckner bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) { 156*2214ed89SReid Kleckner return LineEntry.getColumn() != 0; 157*2214ed89SReid Kleckner }); 158*2214ed89SReid Kleckner OS.EmitIntValue(HaveColumns ? int(codeview::LineFlags::HaveColumns) : 0, 2); 159*2214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4); 160*2214ed89SReid Kleckner 161*2214ed89SReid Kleckner for (auto I = Locs.begin(), E = Locs.end(); I != E;) { 162*2214ed89SReid Kleckner // Emit a file segment for the run of locations that share a file id. 163*2214ed89SReid Kleckner unsigned CurFileNum = I->getFileNum(); 164*2214ed89SReid Kleckner auto FileSegEnd = 165*2214ed89SReid Kleckner std::find_if(I, E, [CurFileNum](const MCCVLineEntry &Loc) { 166*2214ed89SReid Kleckner return Loc.getFileNum() != CurFileNum; 167*2214ed89SReid Kleckner }); 168*2214ed89SReid Kleckner unsigned EntryCount = FileSegEnd - I; 169*2214ed89SReid Kleckner OS.AddComment("Segment for file '" + Twine(Filenames[CurFileNum - 1]) + 170*2214ed89SReid Kleckner "' begins"); 171*2214ed89SReid Kleckner OS.EmitIntValue(8 * (CurFileNum - 1), 4); 172*2214ed89SReid Kleckner OS.EmitIntValue(EntryCount, 4); 173*2214ed89SReid Kleckner uint32_t SegmentSize = 12; 174*2214ed89SReid Kleckner SegmentSize += 8 * EntryCount; 175*2214ed89SReid Kleckner if (HaveColumns) 176*2214ed89SReid Kleckner SegmentSize += 4 * EntryCount; 177*2214ed89SReid Kleckner OS.EmitIntValue(SegmentSize, 4); 178*2214ed89SReid Kleckner 179*2214ed89SReid Kleckner for (auto J = I; J != FileSegEnd; ++J) { 180*2214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4); 181*2214ed89SReid Kleckner unsigned LineData = J->getLine(); 182*2214ed89SReid Kleckner if (J->isStmt()) 183*2214ed89SReid Kleckner LineData |= codeview::LineInfo::StatementFlag; 184*2214ed89SReid Kleckner OS.EmitIntValue(LineData, 4); 185*2214ed89SReid Kleckner } 186*2214ed89SReid Kleckner if (HaveColumns) { 187*2214ed89SReid Kleckner for (auto J = I; J != FileSegEnd; ++J) { 188*2214ed89SReid Kleckner OS.EmitIntValue(J->getColumn(), 2); 189*2214ed89SReid Kleckner OS.EmitIntValue(0, 2); 190*2214ed89SReid Kleckner } 191*2214ed89SReid Kleckner } 192*2214ed89SReid Kleckner I = FileSegEnd; 193*2214ed89SReid Kleckner } 194*2214ed89SReid Kleckner OS.EmitLabel(LineEnd); 195*2214ed89SReid Kleckner } 196*2214ed89SReid Kleckner 197*2214ed89SReid Kleckner // 198*2214ed89SReid Kleckner // This is called when an instruction is assembled into the specified section 199*2214ed89SReid Kleckner // and if there is information from the last .cv_loc directive that has yet to have 200*2214ed89SReid Kleckner // a line entry made for it is made. 201*2214ed89SReid Kleckner // 202*2214ed89SReid Kleckner void MCCVLineEntry::Make(MCObjectStreamer *MCOS) { 203*2214ed89SReid Kleckner if (!MCOS->getContext().getCVLocSeen()) 204*2214ed89SReid Kleckner return; 205*2214ed89SReid Kleckner 206*2214ed89SReid Kleckner // Create a symbol at in the current section for use in the line entry. 207*2214ed89SReid Kleckner MCSymbol *LineSym = MCOS->getContext().createTempSymbol(); 208*2214ed89SReid Kleckner // Set the value of the symbol to use for the MCCVLineEntry. 209*2214ed89SReid Kleckner MCOS->EmitLabel(LineSym); 210*2214ed89SReid Kleckner 211*2214ed89SReid Kleckner // Get the current .loc info saved in the context. 212*2214ed89SReid Kleckner const MCCVLoc &CVLoc = MCOS->getContext().getCurrentCVLoc(); 213*2214ed89SReid Kleckner 214*2214ed89SReid Kleckner // Create a (local) line entry with the symbol and the current .loc info. 215*2214ed89SReid Kleckner MCCVLineEntry LineEntry(LineSym, CVLoc); 216*2214ed89SReid Kleckner 217*2214ed89SReid Kleckner // clear CVLocSeen saying the current .loc info is now used. 218*2214ed89SReid Kleckner MCOS->getContext().clearCVLocSeen(); 219*2214ed89SReid Kleckner 220*2214ed89SReid Kleckner // Add the line entry to this section's entries. 221*2214ed89SReid Kleckner MCOS->getContext().getCVContext().addLineEntry(LineEntry); 222*2214ed89SReid Kleckner } 223