/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/MC/MCCodeView.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- 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/ADT/StringExtras.h" |
17 | | #include "llvm/BinaryFormat/COFF.h" |
18 | | #include "llvm/DebugInfo/CodeView/CodeView.h" |
19 | | #include "llvm/DebugInfo/CodeView/Line.h" |
20 | | #include "llvm/DebugInfo/CodeView/SymbolRecord.h" |
21 | | #include "llvm/MC/MCAsmLayout.h" |
22 | | #include "llvm/MC/MCContext.h" |
23 | | #include "llvm/MC/MCObjectStreamer.h" |
24 | | #include "llvm/MC/MCValue.h" |
25 | | #include "llvm/Support/EndianStream.h" |
26 | | |
27 | | using namespace llvm; |
28 | | using namespace llvm::codeview; |
29 | | |
30 | 20.8k | CodeViewContext::CodeViewContext() {} |
31 | | |
32 | 20.8k | CodeViewContext::~CodeViewContext() { |
33 | 20.8k | // If someone inserted strings into the string table but never actually |
34 | 20.8k | // emitted them somewhere, clean up the fragment. |
35 | 20.8k | if (!InsertedStrTabFragment) |
36 | 20.7k | delete StrTabFragment; |
37 | 20.8k | } |
38 | | |
39 | | /// This is a valid number for use with .cv_loc if we've already seen a .cv_file |
40 | | /// for it. |
41 | 91 | bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const { |
42 | 91 | unsigned Idx = FileNumber - 1; |
43 | 91 | if (Idx < Files.size()) |
44 | 90 | return Files[Idx].Assigned; |
45 | 1 | return false; |
46 | 1 | } |
47 | | |
48 | | bool CodeViewContext::addFile(MCStreamer &OS, unsigned FileNumber, |
49 | | StringRef Filename, |
50 | | ArrayRef<uint8_t> ChecksumBytes, |
51 | 113 | uint8_t ChecksumKind) { |
52 | 113 | assert(FileNumber > 0); |
53 | 113 | auto FilenameOffset = addToStringTable(Filename); |
54 | 113 | Filename = FilenameOffset.first; |
55 | 113 | unsigned Idx = FileNumber - 1; |
56 | 113 | if (Idx >= Files.size()) |
57 | 113 | Files.resize(Idx + 1); |
58 | 113 | |
59 | 113 | if (Filename.empty()) |
60 | 0 | Filename = "<stdin>"; |
61 | 113 | |
62 | 113 | if (Files[Idx].Assigned) |
63 | 0 | return false; |
64 | 113 | |
65 | 113 | FilenameOffset = addToStringTable(Filename); |
66 | 113 | Filename = FilenameOffset.first; |
67 | 113 | unsigned Offset = FilenameOffset.second; |
68 | 113 | |
69 | 113 | auto ChecksumOffsetSymbol = |
70 | 113 | OS.getContext().createTempSymbol("checksum_offset", false); |
71 | 113 | Files[Idx].StringTableOffset = Offset; |
72 | 113 | Files[Idx].ChecksumTableOffset = ChecksumOffsetSymbol; |
73 | 113 | Files[Idx].Assigned = true; |
74 | 113 | Files[Idx].Checksum = ChecksumBytes; |
75 | 113 | Files[Idx].ChecksumKind = ChecksumKind; |
76 | 113 | |
77 | 113 | return true; |
78 | 113 | } |
79 | | |
80 | 158 | bool CodeViewContext::recordFunctionId(unsigned FuncId) { |
81 | 158 | if (FuncId >= Functions.size()) |
82 | 158 | Functions.resize(FuncId + 1); |
83 | 158 | |
84 | 158 | // Return false if this function info was already allocated. |
85 | 158 | if (!Functions[FuncId].isUnallocatedFunctionInfo()) |
86 | 0 | return false; |
87 | 158 | |
88 | 158 | // Mark this as an allocated normal function, and leave the rest alone. |
89 | 158 | Functions[FuncId].ParentFuncIdPlusOne = MCCVFunctionInfo::FunctionSentinel; |
90 | 158 | return true; |
91 | 158 | } |
92 | | |
93 | | bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc, |
94 | | unsigned IAFile, unsigned IALine, |
95 | 31 | unsigned IACol) { |
96 | 31 | if (FuncId >= Functions.size()) |
97 | 30 | Functions.resize(FuncId + 1); |
98 | 31 | |
99 | 31 | // Return false if this function info was already allocated. |
100 | 31 | if (!Functions[FuncId].isUnallocatedFunctionInfo()) |
101 | 1 | return false; |
102 | 30 | |
103 | 30 | MCCVFunctionInfo::LineInfo InlinedAt; |
104 | 30 | InlinedAt.File = IAFile; |
105 | 30 | InlinedAt.Line = IALine; |
106 | 30 | InlinedAt.Col = IACol; |
107 | 30 | |
108 | 30 | // Mark this as an inlined call site and record call site line info. |
109 | 30 | MCCVFunctionInfo *Info = &Functions[FuncId]; |
110 | 30 | Info->ParentFuncIdPlusOne = IAFunc + 1; |
111 | 30 | Info->InlinedAt = InlinedAt; |
112 | 30 | |
113 | 30 | // Walk up the call chain adding this function id to the InlinedAtMap of all |
114 | 30 | // transitive callers until we hit a real function. |
115 | 68 | while (Info->isInlinedCallSite()68 ) { |
116 | 38 | InlinedAt = Info->InlinedAt; |
117 | 38 | Info = getCVFunctionInfo(Info->getParentFuncId()); |
118 | 38 | Info->InlinedAtMap[FuncId] = InlinedAt; |
119 | 38 | } |
120 | 31 | |
121 | 31 | return true; |
122 | 31 | } |
123 | | |
124 | 393 | MCDataFragment *CodeViewContext::getStringTableFragment() { |
125 | 393 | if (!StrTabFragment393 ) { |
126 | 114 | StrTabFragment = new MCDataFragment(); |
127 | 114 | // Start a new string table out with a null byte. |
128 | 114 | StrTabFragment->getContents().push_back('\0'); |
129 | 114 | } |
130 | 393 | return StrTabFragment; |
131 | 393 | } |
132 | | |
133 | 226 | std::pair<StringRef, unsigned> CodeViewContext::addToStringTable(StringRef S) { |
134 | 226 | SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents(); |
135 | 226 | auto Insertion = |
136 | 226 | StringTable.insert(std::make_pair(S, unsigned(Contents.size()))); |
137 | 226 | // Return the string from the table, since it is stable. |
138 | 226 | std::pair<StringRef, unsigned> Ret = |
139 | 226 | std::make_pair(Insertion.first->first(), Insertion.first->second); |
140 | 226 | if (Insertion.second226 ) { |
141 | 113 | // The string map key is always null terminated. |
142 | 113 | Contents.append(Ret.first.begin(), Ret.first.end() + 1); |
143 | 113 | } |
144 | 226 | return Ret; |
145 | 226 | } |
146 | | |
147 | 0 | unsigned CodeViewContext::getStringTableOffset(StringRef S) { |
148 | 0 | // A string table offset of zero is always the empty string. |
149 | 0 | if (S.empty()) |
150 | 0 | return 0; |
151 | 0 | auto I = StringTable.find(S); |
152 | 0 | assert(I != StringTable.end()); |
153 | 0 | return I->second; |
154 | 0 | } |
155 | | |
156 | 68 | void CodeViewContext::emitStringTable(MCObjectStreamer &OS) { |
157 | 68 | MCContext &Ctx = OS.getContext(); |
158 | 68 | MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin", false), |
159 | 68 | *StringEnd = Ctx.createTempSymbol("strtab_end", false); |
160 | 68 | |
161 | 68 | OS.EmitIntValue(unsigned(DebugSubsectionKind::StringTable), 4); |
162 | 68 | OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4); |
163 | 68 | OS.EmitLabel(StringBegin); |
164 | 68 | |
165 | 68 | // Put the string table data fragment here, if we haven't already put it |
166 | 68 | // somewhere else. If somebody wants two string tables in their .s file, one |
167 | 68 | // will just be empty. |
168 | 68 | if (!InsertedStrTabFragment68 ) { |
169 | 68 | OS.insert(getStringTableFragment()); |
170 | 68 | InsertedStrTabFragment = true; |
171 | 68 | } |
172 | 68 | |
173 | 68 | OS.EmitValueToAlignment(4, 0); |
174 | 68 | |
175 | 68 | OS.EmitLabel(StringEnd); |
176 | 68 | } |
177 | | |
178 | 68 | void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) { |
179 | 68 | // Do nothing if there are no file checksums. Microsoft's linker rejects empty |
180 | 68 | // CodeView substreams. |
181 | 68 | if (Files.empty()) |
182 | 15 | return; |
183 | 53 | |
184 | 53 | MCContext &Ctx = OS.getContext(); |
185 | 53 | MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin", false), |
186 | 53 | *FileEnd = Ctx.createTempSymbol("filechecksums_end", false); |
187 | 53 | |
188 | 53 | OS.EmitIntValue(unsigned(DebugSubsectionKind::FileChecksums), 4); |
189 | 53 | OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4); |
190 | 53 | OS.EmitLabel(FileBegin); |
191 | 53 | |
192 | 53 | unsigned CurrentOffset = 0; |
193 | 53 | |
194 | 53 | // Emit an array of FileChecksum entries. We index into this table using the |
195 | 53 | // user-provided file number. Each entry may be a variable number of bytes |
196 | 53 | // determined by the checksum kind and size. |
197 | 60 | for (auto File : Files) { |
198 | 60 | OS.EmitAssignment(File.ChecksumTableOffset, |
199 | 60 | MCConstantExpr::create(CurrentOffset, Ctx)); |
200 | 60 | CurrentOffset += 4; // String table offset. |
201 | 60 | if (!File.ChecksumKind60 ) { |
202 | 45 | CurrentOffset += |
203 | 45 | 4; // One byte each for checksum size and kind, then align to 4 bytes. |
204 | 60 | } else { |
205 | 15 | CurrentOffset += 2; // One byte each for checksum size and kind. |
206 | 15 | CurrentOffset += File.Checksum.size(); |
207 | 15 | CurrentOffset = alignTo(CurrentOffset, 4); |
208 | 15 | } |
209 | 60 | |
210 | 60 | OS.EmitIntValue(File.StringTableOffset, 4); |
211 | 60 | |
212 | 60 | if (!File.ChecksumKind60 ) { |
213 | 45 | // There is no checksum. Therefore zero the next two fields and align |
214 | 45 | // back to 4 bytes. |
215 | 45 | OS.EmitIntValue(0, 4); |
216 | 45 | continue; |
217 | 45 | } |
218 | 15 | OS.EmitIntValue(static_cast<uint8_t>(File.Checksum.size()), 1); |
219 | 15 | OS.EmitIntValue(File.ChecksumKind, 1); |
220 | 15 | OS.EmitBytes(toStringRef(File.Checksum)); |
221 | 15 | OS.EmitValueToAlignment(4); |
222 | 15 | } |
223 | 68 | |
224 | 68 | OS.EmitLabel(FileEnd); |
225 | 68 | |
226 | 68 | ChecksumOffsetsAssigned = true; |
227 | 68 | } |
228 | | |
229 | | // Output checksum table offset of the given file number. It is possible that |
230 | | // not all files have been registered yet, and so the offset cannot be |
231 | | // calculated. In this case a symbol representing the offset is emitted, and |
232 | | // the value of this symbol will be fixed up at a later time. |
233 | | void CodeViewContext::emitFileChecksumOffset(MCObjectStreamer &OS, |
234 | 115 | unsigned FileNo) { |
235 | 115 | unsigned Idx = FileNo - 1; |
236 | 115 | |
237 | 115 | if (Idx >= Files.size()) |
238 | 0 | Files.resize(Idx + 1); |
239 | 115 | |
240 | 115 | if (ChecksumOffsetsAssigned115 ) { |
241 | 3 | OS.EmitSymbolValue(Files[Idx].ChecksumTableOffset, 4); |
242 | 3 | return; |
243 | 3 | } |
244 | 112 | |
245 | 112 | const MCSymbolRefExpr *SRE = |
246 | 112 | MCSymbolRefExpr::create(Files[Idx].ChecksumTableOffset, OS.getContext()); |
247 | 112 | |
248 | 112 | OS.EmitValueImpl(SRE, 4); |
249 | 112 | } |
250 | | |
251 | | void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS, |
252 | | unsigned FuncId, |
253 | | const MCSymbol *FuncBegin, |
254 | 94 | const MCSymbol *FuncEnd) { |
255 | 94 | MCContext &Ctx = OS.getContext(); |
256 | 94 | MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin", false), |
257 | 94 | *LineEnd = Ctx.createTempSymbol("linetable_end", false); |
258 | 94 | |
259 | 94 | OS.EmitIntValue(unsigned(DebugSubsectionKind::Lines), 4); |
260 | 94 | OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4); |
261 | 94 | OS.EmitLabel(LineBegin); |
262 | 94 | OS.EmitCOFFSecRel32(FuncBegin, /*Offset=*/0); |
263 | 94 | OS.EmitCOFFSectionIndex(FuncBegin); |
264 | 94 | |
265 | 94 | // Actual line info. |
266 | 94 | std::vector<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId); |
267 | 170 | bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) { |
268 | 170 | return LineEntry.getColumn() != 0; |
269 | 170 | }); |
270 | 94 | OS.EmitIntValue(HaveColumns ? int(LF_HaveColumns)73 : 021 , 2); |
271 | 94 | OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4); |
272 | 94 | |
273 | 193 | for (auto I = Locs.begin(), E = Locs.end(); I != E193 ;) { |
274 | 99 | // Emit a file segment for the run of locations that share a file id. |
275 | 99 | unsigned CurFileNum = I->getFileNum(); |
276 | 99 | auto FileSegEnd = |
277 | 304 | std::find_if(I, E, [CurFileNum](const MCCVLineEntry &Loc) { |
278 | 304 | return Loc.getFileNum() != CurFileNum; |
279 | 304 | }); |
280 | 99 | unsigned EntryCount = FileSegEnd - I; |
281 | 99 | OS.AddComment( |
282 | 99 | "Segment for file '" + |
283 | 99 | Twine(getStringTableFragment() |
284 | 99 | ->getContents()[Files[CurFileNum - 1].StringTableOffset]) + |
285 | 99 | "' begins"); |
286 | 99 | OS.EmitCVFileChecksumOffsetDirective(CurFileNum); |
287 | 99 | OS.EmitIntValue(EntryCount, 4); |
288 | 99 | uint32_t SegmentSize = 12; |
289 | 99 | SegmentSize += 8 * EntryCount; |
290 | 99 | if (HaveColumns) |
291 | 75 | SegmentSize += 4 * EntryCount; |
292 | 99 | OS.EmitIntValue(SegmentSize, 4); |
293 | 99 | |
294 | 395 | for (auto J = I; J != FileSegEnd395 ; ++J296 ) { |
295 | 296 | OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4); |
296 | 296 | unsigned LineData = J->getLine(); |
297 | 296 | if (J->isStmt()) |
298 | 1 | LineData |= LineInfo::StatementFlag; |
299 | 296 | OS.EmitIntValue(LineData, 4); |
300 | 296 | } |
301 | 99 | if (HaveColumns99 ) { |
302 | 330 | for (auto J = I; J != FileSegEnd330 ; ++J255 ) { |
303 | 255 | OS.EmitIntValue(J->getColumn(), 2); |
304 | 255 | OS.EmitIntValue(0, 2); |
305 | 255 | } |
306 | 75 | } |
307 | 99 | I = FileSegEnd; |
308 | 99 | } |
309 | 94 | OS.EmitLabel(LineEnd); |
310 | 94 | } |
311 | | |
312 | 426 | static bool compressAnnotation(uint32_t Data, SmallVectorImpl<char> &Buffer) { |
313 | 426 | if (isUInt<7>(Data)426 ) { |
314 | 426 | Buffer.push_back(Data); |
315 | 426 | return true; |
316 | 426 | } |
317 | 0 |
|
318 | 0 | if (0 isUInt<14>(Data)0 ) { |
319 | 0 | Buffer.push_back((Data >> 8) | 0x80); |
320 | 0 | Buffer.push_back(Data & 0xff); |
321 | 0 | return true; |
322 | 0 | } |
323 | 0 |
|
324 | 0 | if (0 isUInt<29>(Data)0 ) { |
325 | 0 | Buffer.push_back((Data >> 24) | 0xC0); |
326 | 0 | Buffer.push_back((Data >> 16) & 0xff); |
327 | 0 | Buffer.push_back((Data >> 8) & 0xff); |
328 | 0 | Buffer.push_back(Data & 0xff); |
329 | 0 | return true; |
330 | 0 | } |
331 | 0 |
|
332 | 0 | return false; |
333 | 0 | } |
334 | | |
335 | | static bool compressAnnotation(BinaryAnnotationsOpCode Annotation, |
336 | 213 | SmallVectorImpl<char> &Buffer) { |
337 | 213 | return compressAnnotation(static_cast<uint32_t>(Annotation), Buffer); |
338 | 213 | } |
339 | | |
340 | 123 | static uint32_t encodeSignedNumber(uint32_t Data) { |
341 | 123 | if (Data >> 31) |
342 | 3 | return ((-Data) << 1) | 1; |
343 | 120 | return Data << 1; |
344 | 120 | } |
345 | | |
346 | | void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS, |
347 | | unsigned PrimaryFunctionId, |
348 | | unsigned SourceFileId, |
349 | | unsigned SourceLineNum, |
350 | | const MCSymbol *FnStartSym, |
351 | 22 | const MCSymbol *FnEndSym) { |
352 | 22 | // Create and insert a fragment into the current section that will be encoded |
353 | 22 | // later. |
354 | 22 | new MCCVInlineLineTableFragment(PrimaryFunctionId, SourceFileId, |
355 | 22 | SourceLineNum, FnStartSym, FnEndSym, |
356 | 22 | OS.getCurrentSectionOnly()); |
357 | 22 | } |
358 | | |
359 | | void CodeViewContext::emitDefRange( |
360 | | MCObjectStreamer &OS, |
361 | | ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, |
362 | 106 | StringRef FixedSizePortion) { |
363 | 106 | // Create and insert a fragment into the current section that will be encoded |
364 | 106 | // later. |
365 | 106 | new MCCVDefRangeFragment(Ranges, FixedSizePortion, |
366 | 106 | OS.getCurrentSectionOnly()); |
367 | 106 | } |
368 | | |
369 | | static unsigned computeLabelDiff(MCAsmLayout &Layout, const MCSymbol *Begin, |
370 | 591 | const MCSymbol *End) { |
371 | 591 | MCContext &Ctx = Layout.getAssembler().getContext(); |
372 | 591 | MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; |
373 | 591 | const MCExpr *BeginRef = MCSymbolRefExpr::create(Begin, Variant, Ctx), |
374 | 591 | *EndRef = MCSymbolRefExpr::create(End, Variant, Ctx); |
375 | 591 | const MCExpr *AddrDelta = |
376 | 591 | MCBinaryExpr::create(MCBinaryExpr::Sub, EndRef, BeginRef, Ctx); |
377 | 591 | int64_t Result; |
378 | 591 | bool Success = AddrDelta->evaluateKnownAbsolute(Result, Layout); |
379 | 591 | assert(Success && "failed to evaluate label difference as absolute"); |
380 | 591 | (void)Success; |
381 | 591 | assert(Result >= 0 && "negative label difference requested"); |
382 | 591 | assert(Result < UINT_MAX && "label difference greater than 2GB"); |
383 | 591 | return unsigned(Result); |
384 | 591 | } |
385 | | |
386 | | void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout, |
387 | 66 | MCCVInlineLineTableFragment &Frag) { |
388 | 66 | size_t LocBegin; |
389 | 66 | size_t LocEnd; |
390 | 66 | std::tie(LocBegin, LocEnd) = getLineExtent(Frag.SiteFuncId); |
391 | 66 | |
392 | 66 | // Include all child inline call sites in our .cv_loc extent. |
393 | 66 | MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId); |
394 | 18 | for (auto &KV : SiteInfo->InlinedAtMap) { |
395 | 18 | unsigned ChildId = KV.first; |
396 | 18 | auto Extent = getLineExtent(ChildId); |
397 | 18 | LocBegin = std::min(LocBegin, Extent.first); |
398 | 18 | LocEnd = std::max(LocEnd, Extent.second); |
399 | 18 | } |
400 | 66 | |
401 | 66 | if (LocBegin >= LocEnd) |
402 | 0 | return; |
403 | 66 | ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd); |
404 | 66 | if (Locs.empty()) |
405 | 0 | return; |
406 | 66 | |
407 | 66 | // Make an artificial start location using the function start and the inlinee |
408 | 66 | // lines start location information. All deltas start relative to this |
409 | 66 | // location. |
410 | 66 | MCCVLineEntry StartLoc(Frag.getFnStartSym(), MCCVLoc(Locs.front())); |
411 | 66 | StartLoc.setFileNum(Frag.StartFileId); |
412 | 66 | StartLoc.setLine(Frag.StartLineNum); |
413 | 66 | bool HaveOpenRange = false; |
414 | 66 | |
415 | 66 | const MCSymbol *LastLabel = Frag.getFnStartSym(); |
416 | 66 | MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc; |
417 | 66 | LastSourceLoc.File = Frag.StartFileId; |
418 | 66 | LastSourceLoc.Line = Frag.StartLineNum; |
419 | 66 | |
420 | 66 | SmallVectorImpl<char> &Buffer = Frag.getContents(); |
421 | 66 | Buffer.clear(); // Clear old contents if we went through relaxation. |
422 | 147 | for (const MCCVLineEntry &Loc : Locs) { |
423 | 147 | // Exit early if our line table would produce an oversized InlineSiteSym |
424 | 147 | // record. Account for the ChangeCodeLength annotation emitted after the |
425 | 147 | // loop ends. |
426 | 147 | constexpr uint32_t InlineSiteSize = 12; |
427 | 147 | constexpr uint32_t AnnotationSize = 8; |
428 | 147 | size_t MaxBufferSize = MaxRecordLength - InlineSiteSize - AnnotationSize; |
429 | 147 | if (Buffer.size() >= MaxBufferSize) |
430 | 0 | break; |
431 | 147 | |
432 | 147 | if (147 Loc.getFunctionId() == Frag.SiteFuncId147 ) { |
433 | 108 | CurSourceLoc.File = Loc.getFileNum(); |
434 | 108 | CurSourceLoc.Line = Loc.getLine(); |
435 | 147 | } else { |
436 | 39 | auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId()); |
437 | 39 | if (I != SiteInfo->InlinedAtMap.end()39 ) { |
438 | 33 | // This .cv_loc is from a child inline call site. Use the source |
439 | 33 | // location of the inlined call site instead of the .cv_loc directive |
440 | 33 | // source location. |
441 | 33 | CurSourceLoc = I->second; |
442 | 39 | } else { |
443 | 6 | // We've hit a cv_loc not attributed to this inline call site. Use this |
444 | 6 | // label to end the PC range. |
445 | 6 | if (HaveOpenRange6 ) { |
446 | 3 | unsigned Length = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); |
447 | 3 | compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer); |
448 | 3 | compressAnnotation(Length, Buffer); |
449 | 3 | LastLabel = Loc.getLabel(); |
450 | 3 | } |
451 | 6 | HaveOpenRange = false; |
452 | 6 | continue; |
453 | 6 | } |
454 | 141 | } |
455 | 141 | |
456 | 141 | // Skip this .cv_loc if we have an open range and this isn't a meaningful |
457 | 141 | // source location update. The current table format does not support column |
458 | 141 | // info, so we can skip updates for those. |
459 | 141 | if (141 HaveOpenRange && 141 CurSourceLoc.File == LastSourceLoc.File72 && |
460 | 66 | CurSourceLoc.Line == LastSourceLoc.Line) |
461 | 18 | continue; |
462 | 123 | |
463 | 123 | HaveOpenRange = true; |
464 | 123 | |
465 | 123 | if (CurSourceLoc.File != LastSourceLoc.File123 ) { |
466 | 6 | unsigned FileOffset = static_cast<const MCConstantExpr *>( |
467 | 6 | Files[CurSourceLoc.File - 1] |
468 | 6 | .ChecksumTableOffset->getVariableValue()) |
469 | 6 | ->getValue(); |
470 | 6 | compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer); |
471 | 6 | compressAnnotation(FileOffset, Buffer); |
472 | 6 | } |
473 | 123 | |
474 | 123 | int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line; |
475 | 123 | unsigned EncodedLineDelta = encodeSignedNumber(LineDelta); |
476 | 123 | unsigned CodeDelta = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); |
477 | 123 | if (CodeDelta == 0 && 123 LineDelta != 018 ) { |
478 | 12 | compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer); |
479 | 12 | compressAnnotation(EncodedLineDelta, Buffer); |
480 | 123 | } else if (111 EncodedLineDelta < 0x8 && 111 CodeDelta <= 0xf111 ) { |
481 | 90 | // The ChangeCodeOffsetAndLineOffset combination opcode is used when the |
482 | 90 | // encoded line delta uses 3 or fewer set bits and the code offset fits |
483 | 90 | // in one nibble. |
484 | 90 | unsigned Operand = (EncodedLineDelta << 4) | CodeDelta; |
485 | 90 | compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset, |
486 | 90 | Buffer); |
487 | 90 | compressAnnotation(Operand, Buffer); |
488 | 111 | } else { |
489 | 21 | // Otherwise use the separate line and code deltas. |
490 | 21 | if (LineDelta != 021 ) { |
491 | 15 | compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer); |
492 | 15 | compressAnnotation(EncodedLineDelta, Buffer); |
493 | 15 | } |
494 | 111 | compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffset, Buffer); |
495 | 111 | compressAnnotation(CodeDelta, Buffer); |
496 | 111 | } |
497 | 147 | |
498 | 147 | LastLabel = Loc.getLabel(); |
499 | 147 | LastSourceLoc = CurSourceLoc; |
500 | 147 | } |
501 | 66 | |
502 | 66 | assert(HaveOpenRange); |
503 | 66 | |
504 | 66 | unsigned EndSymLength = |
505 | 66 | computeLabelDiff(Layout, LastLabel, Frag.getFnEndSym()); |
506 | 66 | unsigned LocAfterLength = ~0U; |
507 | 66 | ArrayRef<MCCVLineEntry> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1); |
508 | 66 | if (!LocAfter.empty()66 ) { |
509 | 54 | // Only try to compute this difference if we're in the same section. |
510 | 54 | const MCCVLineEntry &Loc = LocAfter[0]; |
511 | 54 | if (&Loc.getLabel()->getSection(false) == &LastLabel->getSection(false)) |
512 | 51 | LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel()); |
513 | 54 | } |
514 | 66 | |
515 | 66 | compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer); |
516 | 66 | compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer); |
517 | 66 | } |
518 | | |
519 | | void CodeViewContext::encodeDefRange(MCAsmLayout &Layout, |
520 | 318 | MCCVDefRangeFragment &Frag) { |
521 | 318 | MCContext &Ctx = Layout.getAssembler().getContext(); |
522 | 318 | SmallVectorImpl<char> &Contents = Frag.getContents(); |
523 | 318 | Contents.clear(); |
524 | 318 | SmallVectorImpl<MCFixup> &Fixups = Frag.getFixups(); |
525 | 318 | Fixups.clear(); |
526 | 318 | raw_svector_ostream OS(Contents); |
527 | 318 | |
528 | 318 | // Compute all the sizes up front. |
529 | 318 | SmallVector<std::pair<unsigned, unsigned>, 4> GapAndRangeSizes; |
530 | 318 | const MCSymbol *LastLabel = nullptr; |
531 | 333 | for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) { |
532 | 333 | unsigned GapSize = |
533 | 333 | LastLabel ? computeLabelDiff(Layout, LastLabel, Range.first)15 : 0318 ; |
534 | 333 | unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second); |
535 | 333 | GapAndRangeSizes.push_back({GapSize, RangeSize}); |
536 | 333 | LastLabel = Range.second; |
537 | 333 | } |
538 | 318 | |
539 | 318 | // Write down each range where the variable is defined. |
540 | 642 | for (size_t I = 0, E = Frag.getRanges().size(); I != E642 ;) { |
541 | 324 | // If the range size of multiple consecutive ranges is under the max, |
542 | 324 | // combine the ranges and emit some gaps. |
543 | 324 | const MCSymbol *RangeBegin = Frag.getRanges()[I].first; |
544 | 324 | unsigned RangeSize = GapAndRangeSizes[I].second; |
545 | 324 | size_t J = I + 1; |
546 | 333 | for (; J != E333 ; ++J9 ) { |
547 | 15 | unsigned GapAndRangeSize = GapAndRangeSizes[J].first + GapAndRangeSizes[J].second; |
548 | 15 | if (RangeSize + GapAndRangeSize > MaxDefRange) |
549 | 6 | break; |
550 | 9 | RangeSize += GapAndRangeSize; |
551 | 9 | } |
552 | 324 | unsigned NumGaps = J - I - 1; |
553 | 324 | |
554 | 324 | support::endian::Writer<support::little> LEWriter(OS); |
555 | 324 | |
556 | 324 | unsigned Bias = 0; |
557 | 324 | // We must split the range into chunks of MaxDefRange, this is a fundamental |
558 | 324 | // limitation of the file format. |
559 | 324 | do { |
560 | 324 | uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize); |
561 | 324 | |
562 | 324 | const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(RangeBegin, Ctx); |
563 | 324 | const MCBinaryExpr *BE = |
564 | 324 | MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx); |
565 | 324 | MCValue Res; |
566 | 324 | BE->evaluateAsRelocatable(Res, &Layout, /*Fixup=*/nullptr); |
567 | 324 | |
568 | 324 | // Each record begins with a 2-byte number indicating how large the record |
569 | 324 | // is. |
570 | 324 | StringRef FixedSizePortion = Frag.getFixedSizePortion(); |
571 | 324 | // Our record is a fixed sized prefix and a LocalVariableAddrRange that we |
572 | 324 | // are artificially constructing. |
573 | 324 | size_t RecordSize = FixedSizePortion.size() + |
574 | 324 | sizeof(LocalVariableAddrRange) + 4 * NumGaps; |
575 | 324 | // Write out the record size. |
576 | 324 | LEWriter.write<uint16_t>(RecordSize); |
577 | 324 | // Write out the fixed size prefix. |
578 | 324 | OS << FixedSizePortion; |
579 | 324 | // Make space for a fixup that will eventually have a section relative |
580 | 324 | // relocation pointing at the offset where the variable becomes live. |
581 | 324 | Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4)); |
582 | 324 | LEWriter.write<uint32_t>(0); // Fixup for code start. |
583 | 324 | // Make space for a fixup that will record the section index for the code. |
584 | 324 | Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2)); |
585 | 324 | LEWriter.write<uint16_t>(0); // Fixup for section index. |
586 | 324 | // Write down the range's extent. |
587 | 324 | LEWriter.write<uint16_t>(Chunk); |
588 | 324 | |
589 | 324 | // Move on to the next range. |
590 | 324 | Bias += Chunk; |
591 | 324 | RangeSize -= Chunk; |
592 | 324 | } while (RangeSize > 0); |
593 | 324 | |
594 | 324 | // Emit the gaps afterwards. |
595 | 324 | assert((NumGaps == 0 || Bias <= MaxDefRange) && |
596 | 324 | "large ranges should not have gaps"); |
597 | 324 | unsigned GapStartOffset = GapAndRangeSizes[I].second; |
598 | 333 | for (++I; I != J333 ; ++I9 ) { |
599 | 9 | unsigned GapSize, RangeSize; |
600 | 9 | assert(I < GapAndRangeSizes.size()); |
601 | 9 | std::tie(GapSize, RangeSize) = GapAndRangeSizes[I]; |
602 | 9 | LEWriter.write<uint16_t>(GapStartOffset); |
603 | 9 | LEWriter.write<uint16_t>(GapSize); |
604 | 9 | GapStartOffset += GapSize + RangeSize; |
605 | 9 | } |
606 | 324 | } |
607 | 318 | } |
608 | | |
609 | | // |
610 | | // This is called when an instruction is assembled into the specified section |
611 | | // and if there is information from the last .cv_loc directive that has yet to have |
612 | | // a line entry made for it is made. |
613 | | // |
614 | 29.2M | void MCCVLineEntry::Make(MCObjectStreamer *MCOS) { |
615 | 29.2M | CodeViewContext &CVC = MCOS->getContext().getCVContext(); |
616 | 29.2M | if (!CVC.getCVLocSeen()) |
617 | 29.2M | return; |
618 | 331 | |
619 | 331 | // Create a symbol at in the current section for use in the line entry. |
620 | 331 | MCSymbol *LineSym = MCOS->getContext().createTempSymbol(); |
621 | 331 | // Set the value of the symbol to use for the MCCVLineEntry. |
622 | 331 | MCOS->EmitLabel(LineSym); |
623 | 331 | |
624 | 331 | // Get the current .loc info saved in the context. |
625 | 331 | const MCCVLoc &CVLoc = CVC.getCurrentCVLoc(); |
626 | 331 | |
627 | 331 | // Create a (local) line entry with the symbol and the current .loc info. |
628 | 331 | MCCVLineEntry LineEntry(LineSym, CVLoc); |
629 | 331 | |
630 | 331 | // clear CVLocSeen saying the current .loc info is now used. |
631 | 331 | CVC.clearCVLocSeen(); |
632 | 331 | |
633 | 331 | // Add the line entry to this section's entries. |
634 | 331 | CVC.addLineEntry(LineEntry); |
635 | 331 | } |