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" 18*6fcbd7e9SDavid Majnemer #include "llvm/DebugInfo/CodeView/SymbolRecord.h" 192214ed89SReid Kleckner #include "llvm/MC/MCContext.h" 202214ed89SReid Kleckner #include "llvm/MC/MCObjectStreamer.h" 212214ed89SReid Kleckner #include "llvm/Support/COFF.h" 222214ed89SReid Kleckner 232214ed89SReid Kleckner using namespace llvm; 242214ed89SReid Kleckner using namespace llvm::codeview; 252214ed89SReid Kleckner 262214ed89SReid Kleckner CodeViewContext::CodeViewContext() {} 272214ed89SReid Kleckner 282214ed89SReid Kleckner CodeViewContext::~CodeViewContext() { 292214ed89SReid Kleckner // If someone inserted strings into the string table but never actually 302214ed89SReid Kleckner // emitted them somewhere, clean up the fragment. 312214ed89SReid Kleckner if (!InsertedStrTabFragment) 322214ed89SReid Kleckner delete StrTabFragment; 332214ed89SReid Kleckner } 342214ed89SReid Kleckner 352214ed89SReid Kleckner /// This is a valid number for use with .cv_loc if we've already seen a .cv_file 362214ed89SReid Kleckner /// for it. 372214ed89SReid Kleckner bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const { 382214ed89SReid Kleckner unsigned Idx = FileNumber - 1; 392214ed89SReid Kleckner if (Idx < Filenames.size()) 402214ed89SReid Kleckner return !Filenames[Idx].empty(); 412214ed89SReid Kleckner return false; 422214ed89SReid Kleckner } 432214ed89SReid Kleckner 442214ed89SReid Kleckner bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) { 452214ed89SReid Kleckner assert(FileNumber > 0); 462214ed89SReid Kleckner Filename = addToStringTable(Filename); 472214ed89SReid Kleckner unsigned Idx = FileNumber - 1; 482214ed89SReid Kleckner if (Idx >= Filenames.size()) 492214ed89SReid Kleckner Filenames.resize(Idx + 1); 502214ed89SReid Kleckner 512214ed89SReid Kleckner if (Filename.empty()) 522214ed89SReid Kleckner Filename = "<stdin>"; 532214ed89SReid Kleckner 542214ed89SReid Kleckner if (!Filenames[Idx].empty()) 552214ed89SReid Kleckner return false; 562214ed89SReid Kleckner 572214ed89SReid Kleckner // FIXME: We should store the string table offset of the filename, rather than 582214ed89SReid Kleckner // the filename itself for efficiency. 592214ed89SReid Kleckner Filename = addToStringTable(Filename); 602214ed89SReid Kleckner 612214ed89SReid Kleckner Filenames[Idx] = Filename; 622214ed89SReid Kleckner return true; 632214ed89SReid Kleckner } 642214ed89SReid Kleckner 652214ed89SReid Kleckner MCDataFragment *CodeViewContext::getStringTableFragment() { 662214ed89SReid Kleckner if (!StrTabFragment) { 672214ed89SReid Kleckner StrTabFragment = new MCDataFragment(); 682214ed89SReid Kleckner // Start a new string table out with a null byte. 692214ed89SReid Kleckner StrTabFragment->getContents().push_back('\0'); 702214ed89SReid Kleckner } 712214ed89SReid Kleckner return StrTabFragment; 722214ed89SReid Kleckner } 732214ed89SReid Kleckner 742214ed89SReid Kleckner StringRef CodeViewContext::addToStringTable(StringRef S) { 752214ed89SReid Kleckner SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents(); 762214ed89SReid Kleckner auto Insertion = 772214ed89SReid Kleckner StringTable.insert(std::make_pair(S, unsigned(Contents.size()))); 782214ed89SReid Kleckner // Return the string from the table, since it is stable. 792214ed89SReid Kleckner S = Insertion.first->first(); 802214ed89SReid Kleckner if (Insertion.second) { 812214ed89SReid Kleckner // The string map key is always null terminated. 822214ed89SReid Kleckner Contents.append(S.begin(), S.end() + 1); 832214ed89SReid Kleckner } 842214ed89SReid Kleckner return S; 852214ed89SReid Kleckner } 862214ed89SReid Kleckner 872214ed89SReid Kleckner unsigned CodeViewContext::getStringTableOffset(StringRef S) { 882214ed89SReid Kleckner // A string table offset of zero is always the empty string. 892214ed89SReid Kleckner if (S.empty()) 902214ed89SReid Kleckner return 0; 912214ed89SReid Kleckner auto I = StringTable.find(S); 922214ed89SReid Kleckner assert(I != StringTable.end()); 932214ed89SReid Kleckner return I->second; 942214ed89SReid Kleckner } 952214ed89SReid Kleckner 962214ed89SReid Kleckner void CodeViewContext::emitStringTable(MCObjectStreamer &OS) { 972214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 98a0b44ef6SDavid Blaikie MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin", false), 99a0b44ef6SDavid Blaikie *StringEnd = Ctx.createTempSymbol("strtab_end", false); 1002214ed89SReid Kleckner 1012214ed89SReid Kleckner OS.EmitIntValue(unsigned(ModuleSubstreamKind::StringTable), 4); 1022214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4); 1032214ed89SReid Kleckner OS.EmitLabel(StringBegin); 1042214ed89SReid Kleckner 1052214ed89SReid Kleckner // Put the string table data fragment here, if we haven't already put it 1062214ed89SReid Kleckner // somewhere else. If somebody wants two string tables in their .s file, one 1072214ed89SReid Kleckner // will just be empty. 1082214ed89SReid Kleckner if (!InsertedStrTabFragment) { 1092214ed89SReid Kleckner OS.insert(getStringTableFragment()); 1102214ed89SReid Kleckner InsertedStrTabFragment = true; 1112214ed89SReid Kleckner } 1122214ed89SReid Kleckner 1132214ed89SReid Kleckner OS.EmitValueToAlignment(4, 0); 1142214ed89SReid Kleckner 1152214ed89SReid Kleckner OS.EmitLabel(StringEnd); 1162214ed89SReid Kleckner } 1172214ed89SReid Kleckner 1182214ed89SReid Kleckner void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) { 1192214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 120a0b44ef6SDavid Blaikie MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin", false), 121a0b44ef6SDavid Blaikie *FileEnd = Ctx.createTempSymbol("filechecksums_end", false); 1222214ed89SReid Kleckner 1232214ed89SReid Kleckner OS.EmitIntValue(unsigned(ModuleSubstreamKind::FileChecksums), 4); 1242214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4); 1252214ed89SReid Kleckner OS.EmitLabel(FileBegin); 1262214ed89SReid Kleckner 1272214ed89SReid Kleckner // Emit an array of FileChecksum entries. We index into this table using the 1282214ed89SReid Kleckner // user-provided file number. Each entry is currently 8 bytes, as we don't 1292214ed89SReid Kleckner // emit checksums. 1302214ed89SReid Kleckner for (StringRef Filename : Filenames) { 1312214ed89SReid Kleckner OS.EmitIntValue(getStringTableOffset(Filename), 4); 1322214ed89SReid Kleckner // Zero the next two fields and align back to 4 bytes. This indicates that 1332214ed89SReid Kleckner // no checksum is present. 1342214ed89SReid Kleckner OS.EmitIntValue(0, 4); 1352214ed89SReid Kleckner } 1362214ed89SReid Kleckner 1372214ed89SReid Kleckner OS.EmitLabel(FileEnd); 1382214ed89SReid Kleckner } 1392214ed89SReid Kleckner 1402214ed89SReid Kleckner void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, 1412214ed89SReid Kleckner unsigned FuncId, 1422214ed89SReid Kleckner const MCSymbol *FuncBegin, 1432214ed89SReid Kleckner const MCSymbol *FuncEnd) { 1442214ed89SReid Kleckner MCContext &Ctx = OS.getContext(); 145a0b44ef6SDavid Blaikie MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin", false), 146a0b44ef6SDavid Blaikie *LineEnd = Ctx.createTempSymbol("linetable_end", false); 1472214ed89SReid Kleckner 1482214ed89SReid Kleckner OS.EmitIntValue(unsigned(ModuleSubstreamKind::Lines), 4); 1492214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4); 1502214ed89SReid Kleckner OS.EmitLabel(LineBegin); 1512214ed89SReid Kleckner OS.EmitCOFFSecRel32(FuncBegin); 1522214ed89SReid Kleckner OS.EmitCOFFSectionIndex(FuncBegin); 1532214ed89SReid Kleckner 1542214ed89SReid Kleckner // Actual line info. 155*6fcbd7e9SDavid Majnemer std::vector<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId); 1562214ed89SReid Kleckner bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) { 1572214ed89SReid Kleckner return LineEntry.getColumn() != 0; 1582214ed89SReid Kleckner }); 159*6fcbd7e9SDavid Majnemer OS.EmitIntValue(HaveColumns ? int(LineFlags::HaveColumns) : 0, 2); 1602214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4); 1612214ed89SReid Kleckner 1622214ed89SReid Kleckner for (auto I = Locs.begin(), E = Locs.end(); I != E;) { 1632214ed89SReid Kleckner // Emit a file segment for the run of locations that share a file id. 1642214ed89SReid Kleckner unsigned CurFileNum = I->getFileNum(); 1652214ed89SReid Kleckner auto FileSegEnd = 1662214ed89SReid Kleckner std::find_if(I, E, [CurFileNum](const MCCVLineEntry &Loc) { 1672214ed89SReid Kleckner return Loc.getFileNum() != CurFileNum; 1682214ed89SReid Kleckner }); 1692214ed89SReid Kleckner unsigned EntryCount = FileSegEnd - I; 1702214ed89SReid Kleckner OS.AddComment("Segment for file '" + Twine(Filenames[CurFileNum - 1]) + 1712214ed89SReid Kleckner "' begins"); 1722214ed89SReid Kleckner OS.EmitIntValue(8 * (CurFileNum - 1), 4); 1732214ed89SReid Kleckner OS.EmitIntValue(EntryCount, 4); 1742214ed89SReid Kleckner uint32_t SegmentSize = 12; 1752214ed89SReid Kleckner SegmentSize += 8 * EntryCount; 1762214ed89SReid Kleckner if (HaveColumns) 1772214ed89SReid Kleckner SegmentSize += 4 * EntryCount; 1782214ed89SReid Kleckner OS.EmitIntValue(SegmentSize, 4); 1792214ed89SReid Kleckner 1802214ed89SReid Kleckner for (auto J = I; J != FileSegEnd; ++J) { 1812214ed89SReid Kleckner OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4); 1822214ed89SReid Kleckner unsigned LineData = J->getLine(); 1832214ed89SReid Kleckner if (J->isStmt()) 184*6fcbd7e9SDavid Majnemer LineData |= LineInfo::StatementFlag; 1852214ed89SReid Kleckner OS.EmitIntValue(LineData, 4); 1862214ed89SReid Kleckner } 1872214ed89SReid Kleckner if (HaveColumns) { 1882214ed89SReid Kleckner for (auto J = I; J != FileSegEnd; ++J) { 1892214ed89SReid Kleckner OS.EmitIntValue(J->getColumn(), 2); 1902214ed89SReid Kleckner OS.EmitIntValue(0, 2); 1912214ed89SReid Kleckner } 1922214ed89SReid Kleckner } 1932214ed89SReid Kleckner I = FileSegEnd; 1942214ed89SReid Kleckner } 1952214ed89SReid Kleckner OS.EmitLabel(LineEnd); 1962214ed89SReid Kleckner } 1972214ed89SReid Kleckner 198*6fcbd7e9SDavid Majnemer static bool compressAnnotation(uint32_t Data, SmallVectorImpl<char> &Buffer) { 199*6fcbd7e9SDavid Majnemer if (isUInt<7>(Data)) { 200*6fcbd7e9SDavid Majnemer Buffer.push_back(Data); 201*6fcbd7e9SDavid Majnemer return true; 202*6fcbd7e9SDavid Majnemer } 203*6fcbd7e9SDavid Majnemer 204*6fcbd7e9SDavid Majnemer if (isUInt<14>(Data)) { 205*6fcbd7e9SDavid Majnemer Buffer.push_back((Data >> 8) | 0x80); 206*6fcbd7e9SDavid Majnemer Buffer.push_back(Data & 0xff); 207*6fcbd7e9SDavid Majnemer return true; 208*6fcbd7e9SDavid Majnemer } 209*6fcbd7e9SDavid Majnemer 210*6fcbd7e9SDavid Majnemer if (isUInt<29>(Data)) { 211*6fcbd7e9SDavid Majnemer Buffer.push_back((Data >> 24) | 0xC0); 212*6fcbd7e9SDavid Majnemer Buffer.push_back((Data >> 16) & 0xff); 213*6fcbd7e9SDavid Majnemer Buffer.push_back((Data >> 8) & 0xff); 214*6fcbd7e9SDavid Majnemer Buffer.push_back(Data & 0xff); 215*6fcbd7e9SDavid Majnemer return true; 216*6fcbd7e9SDavid Majnemer } 217*6fcbd7e9SDavid Majnemer 218*6fcbd7e9SDavid Majnemer return false; 219*6fcbd7e9SDavid Majnemer } 220*6fcbd7e9SDavid Majnemer 221*6fcbd7e9SDavid Majnemer static uint32_t encodeSignedNumber(uint32_t Data) { 222*6fcbd7e9SDavid Majnemer if (Data >> 31) 223*6fcbd7e9SDavid Majnemer return ((-Data) << 1) | 1; 224*6fcbd7e9SDavid Majnemer return Data << 1; 225*6fcbd7e9SDavid Majnemer } 226*6fcbd7e9SDavid Majnemer 227*6fcbd7e9SDavid Majnemer void CodeViewContext::emitInlineLineTableForFunction( 228*6fcbd7e9SDavid Majnemer MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId, 229*6fcbd7e9SDavid Majnemer unsigned SourceLineNum, ArrayRef<unsigned> SecondaryFunctionIds) { 230*6fcbd7e9SDavid Majnemer std::vector<MCCVLineEntry> Locs = getFunctionLineEntries(PrimaryFunctionId); 231*6fcbd7e9SDavid Majnemer std::vector<std::pair<BinaryAnnotationsOpCode, uint32_t>> Annotations; 232*6fcbd7e9SDavid Majnemer 233*6fcbd7e9SDavid Majnemer const MCCVLineEntry *LastLoc = nullptr; 234*6fcbd7e9SDavid Majnemer unsigned LastFileId = SourceFileId; 235*6fcbd7e9SDavid Majnemer unsigned LastLineNum = SourceLineNum; 236*6fcbd7e9SDavid Majnemer 237*6fcbd7e9SDavid Majnemer for (const MCCVLineEntry &Loc : Locs) { 238*6fcbd7e9SDavid Majnemer if (!LastLoc) { 239*6fcbd7e9SDavid Majnemer // TODO ChangeCodeOffset 240*6fcbd7e9SDavid Majnemer // TODO ChangeCodeLength 241*6fcbd7e9SDavid Majnemer } 242*6fcbd7e9SDavid Majnemer 243*6fcbd7e9SDavid Majnemer if (Loc.getFileNum() != LastFileId) 244*6fcbd7e9SDavid Majnemer Annotations.push_back({ChangeFile, Loc.getFileNum()}); 245*6fcbd7e9SDavid Majnemer 246*6fcbd7e9SDavid Majnemer if (Loc.getLine() != LastLineNum) 247*6fcbd7e9SDavid Majnemer Annotations.push_back( 248*6fcbd7e9SDavid Majnemer {ChangeLineOffset, encodeSignedNumber(Loc.getLine() - LastLineNum)}); 249*6fcbd7e9SDavid Majnemer 250*6fcbd7e9SDavid Majnemer LastLoc = &Loc; 251*6fcbd7e9SDavid Majnemer LastFileId = Loc.getFileNum(); 252*6fcbd7e9SDavid Majnemer LastLineNum = Loc.getLine(); 253*6fcbd7e9SDavid Majnemer } 254*6fcbd7e9SDavid Majnemer 255*6fcbd7e9SDavid Majnemer SmallString<32> Buffer; 256*6fcbd7e9SDavid Majnemer for (auto Annotation : Annotations) { 257*6fcbd7e9SDavid Majnemer BinaryAnnotationsOpCode Opcode = Annotation.first; 258*6fcbd7e9SDavid Majnemer uint32_t Operand = Annotation.second; 259*6fcbd7e9SDavid Majnemer compressAnnotation(Opcode, Buffer); 260*6fcbd7e9SDavid Majnemer compressAnnotation(Operand, Buffer); 261*6fcbd7e9SDavid Majnemer } 262*6fcbd7e9SDavid Majnemer OS.EmitBytes(Buffer); 263*6fcbd7e9SDavid Majnemer } 264*6fcbd7e9SDavid Majnemer 2652214ed89SReid Kleckner // 2662214ed89SReid Kleckner // This is called when an instruction is assembled into the specified section 2672214ed89SReid Kleckner // and if there is information from the last .cv_loc directive that has yet to have 2682214ed89SReid Kleckner // a line entry made for it is made. 2692214ed89SReid Kleckner // 2702214ed89SReid Kleckner void MCCVLineEntry::Make(MCObjectStreamer *MCOS) { 2712214ed89SReid Kleckner if (!MCOS->getContext().getCVLocSeen()) 2722214ed89SReid Kleckner return; 2732214ed89SReid Kleckner 2742214ed89SReid Kleckner // Create a symbol at in the current section for use in the line entry. 2752214ed89SReid Kleckner MCSymbol *LineSym = MCOS->getContext().createTempSymbol(); 2762214ed89SReid Kleckner // Set the value of the symbol to use for the MCCVLineEntry. 2772214ed89SReid Kleckner MCOS->EmitLabel(LineSym); 2782214ed89SReid Kleckner 2792214ed89SReid Kleckner // Get the current .loc info saved in the context. 2802214ed89SReid Kleckner const MCCVLoc &CVLoc = MCOS->getContext().getCurrentCVLoc(); 2812214ed89SReid Kleckner 2822214ed89SReid Kleckner // Create a (local) line entry with the symbol and the current .loc info. 2832214ed89SReid Kleckner MCCVLineEntry LineEntry(LineSym, CVLoc); 2842214ed89SReid Kleckner 2852214ed89SReid Kleckner // clear CVLocSeen saying the current .loc info is now used. 2862214ed89SReid Kleckner MCOS->getContext().clearCVLocSeen(); 2872214ed89SReid Kleckner 2882214ed89SReid Kleckner // Add the line entry to this section's entries. 2892214ed89SReid Kleckner MCOS->getContext().getCVContext().addLineEntry(LineEntry); 2902214ed89SReid Kleckner } 291