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