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