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