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