LLVM 22.0.0git
MCCodeView.cpp
Go to the documentation of this file.
1//===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Holds state from .cv_file and .cv_loc directives for later emission.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/MC/MCCodeView.h"
14#include "llvm/ADT/STLExtras.h"
19#include "llvm/MC/MCAssembler.h"
20#include "llvm/MC/MCContext.h"
22#include "llvm/MC/MCValue.h"
24
25using namespace llvm;
26using namespace llvm::codeview;
27
29 if (!StrTabFragment)
30 return;
31 assert(StrTabFragment->getKind() == MCFragment::FT_Data);
32 StrTabFragment->setVarContents(StrTab);
33}
34
35/// This is a valid number for use with .cv_loc if we've already seen a .cv_file
36/// for it.
37bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const {
38 unsigned Idx = FileNumber - 1;
39 if (Idx < Files.size())
40 return Files[Idx].Assigned;
41 return false;
42}
43
44bool CodeViewContext::addFile(MCStreamer &OS, unsigned FileNumber,
45 StringRef Filename,
46 ArrayRef<uint8_t> ChecksumBytes,
47 uint8_t ChecksumKind) {
48 assert(FileNumber > 0);
49 auto FilenameOffset = addToStringTable(Filename);
50 Filename = FilenameOffset.first;
51 unsigned Idx = FileNumber - 1;
52 if (Idx >= Files.size())
53 Files.resize(Idx + 1);
54
55 if (Filename.empty())
56 Filename = "<stdin>";
57
58 if (Files[Idx].Assigned)
59 return false;
60
61 FilenameOffset = addToStringTable(Filename);
62 Filename = FilenameOffset.first;
63 unsigned Offset = FilenameOffset.second;
64
65 auto ChecksumOffsetSymbol =
66 OS.getContext().createTempSymbol("checksum_offset", false);
67 Files[Idx].StringTableOffset = Offset;
68 Files[Idx].ChecksumTableOffset = ChecksumOffsetSymbol;
69 Files[Idx].Assigned = true;
70 Files[Idx].Checksum = ChecksumBytes;
71 Files[Idx].ChecksumKind = ChecksumKind;
72
73 return true;
74}
75
77 if (FuncId >= Functions.size())
78 return nullptr;
79 if (Functions[FuncId].isUnallocatedFunctionInfo())
80 return nullptr;
81 return &Functions[FuncId];
82}
83
84bool CodeViewContext::recordFunctionId(unsigned FuncId) {
85 if (FuncId >= Functions.size())
86 Functions.resize(FuncId + 1);
87
88 // Return false if this function info was already allocated.
89 if (!Functions[FuncId].isUnallocatedFunctionInfo())
90 return false;
91
92 // Mark this as an allocated normal function, and leave the rest alone.
93 Functions[FuncId].ParentFuncIdPlusOne = MCCVFunctionInfo::FunctionSentinel;
94 return true;
95}
96
97bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
98 unsigned IAFile, unsigned IALine,
99 unsigned IACol) {
100 if (FuncId >= Functions.size())
101 Functions.resize(FuncId + 1);
102
103 // Return false if this function info was already allocated.
104 if (!Functions[FuncId].isUnallocatedFunctionInfo())
105 return false;
106
108 InlinedAt.File = IAFile;
109 InlinedAt.Line = IALine;
110 InlinedAt.Col = IACol;
111
112 // Mark this as an inlined call site and record call site line info.
113 MCCVFunctionInfo *Info = &Functions[FuncId];
114 Info->ParentFuncIdPlusOne = IAFunc + 1;
115 Info->InlinedAt = InlinedAt;
116
117 // Walk up the call chain adding this function id to the InlinedAtMap of all
118 // transitive callers until we hit a real function.
119 while (Info->isInlinedCallSite()) {
120 InlinedAt = Info->InlinedAt;
121 Info = getCVFunctionInfo(Info->getParentFuncId());
122 Info->InlinedAtMap[FuncId] = InlinedAt;
123 }
124
125 return true;
126}
127
129 unsigned FunctionId, unsigned FileNo,
130 unsigned Line, unsigned Column,
131 bool PrologueEnd, bool IsStmt) {
133 Label, FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt});
134}
135
136std::pair<StringRef, unsigned> CodeViewContext::addToStringTable(StringRef S) {
137 auto Insertion =
138 StringTable.insert(std::make_pair(S, unsigned(StrTab.size())));
139 // Return the string from the table, since it is stable.
140 std::pair<StringRef, unsigned> Ret =
141 std::make_pair(Insertion.first->first(), Insertion.first->second);
142 if (Insertion.second) {
143 // The string map key is always null terminated.
144 StrTab.append(Ret.first.begin(), Ret.first.end() + 1);
145 }
146 return Ret;
147}
148
149unsigned CodeViewContext::getStringTableOffset(StringRef S) {
150 // A string table offset of zero is always the empty string.
151 if (S.empty())
152 return 0;
153 auto I = StringTable.find(S);
154 assert(I != StringTable.end());
155 return I->second;
156}
157
159 MCContext &Ctx = OS.getContext();
160 MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin", false),
161 *StringEnd = Ctx.createTempSymbol("strtab_end", false);
162
164 OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4);
165 OS.emitLabel(StringBegin);
166
167 // Put the string table data fragment here, if we haven't already put it
168 // somewhere else. If somebody wants two string tables in their .s file, one
169 // will just be empty.
170 if (!StrTabFragment) {
171 OS.newFragment();
172 StrTabFragment = OS.getCurrentFragment();
173 OS.newFragment();
174 }
175
176 OS.emitValueToAlignment(Align(4), 0);
177
178 OS.emitLabel(StringEnd);
179}
180
182 // Do nothing if there are no file checksums. Microsoft's linker rejects empty
183 // CodeView substreams.
184 if (Files.empty())
185 return;
186
187 MCContext &Ctx = OS.getContext();
188 MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin", false),
189 *FileEnd = Ctx.createTempSymbol("filechecksums_end", false);
190
192 OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4);
193 OS.emitLabel(FileBegin);
194
195 unsigned CurrentOffset = 0;
196
197 // Emit an array of FileChecksum entries. We index into this table using the
198 // user-provided file number. Each entry may be a variable number of bytes
199 // determined by the checksum kind and size.
200 for (auto File : Files) {
201 OS.emitAssignment(File.ChecksumTableOffset,
202 MCConstantExpr::create(CurrentOffset, Ctx));
203 CurrentOffset += 4; // String table offset.
204 if (!File.ChecksumKind) {
205 CurrentOffset +=
206 4; // One byte each for checksum size and kind, then align to 4 bytes.
207 } else {
208 CurrentOffset += 2; // One byte each for checksum size and kind.
209 CurrentOffset += File.Checksum.size();
210 CurrentOffset = alignTo(CurrentOffset, 4);
211 }
212
213 OS.emitInt32(File.StringTableOffset);
214
215 if (!File.ChecksumKind) {
216 // There is no checksum. Therefore zero the next two fields and align
217 // back to 4 bytes.
218 OS.emitInt32(0);
219 continue;
220 }
221 OS.emitInt8(static_cast<uint8_t>(File.Checksum.size()));
222 OS.emitInt8(File.ChecksumKind);
223 OS.emitBytes(toStringRef(File.Checksum));
225 }
226
227 OS.emitLabel(FileEnd);
228
229 ChecksumOffsetsAssigned = true;
230}
231
232// Output checksum table offset of the given file number. It is possible that
233// not all files have been registered yet, and so the offset cannot be
234// calculated. In this case a symbol representing the offset is emitted, and
235// the value of this symbol will be fixed up at a later time.
237 unsigned FileNo) {
238 unsigned Idx = FileNo - 1;
239
240 if (Idx >= Files.size())
241 Files.resize(Idx + 1);
242
243 if (ChecksumOffsetsAssigned) {
244 OS.emitSymbolValue(Files[Idx].ChecksumTableOffset, 4);
245 return;
246 }
247
248 const MCSymbolRefExpr *SRE =
249 MCSymbolRefExpr::create(Files[Idx].ChecksumTableOffset, OS.getContext());
250
251 OS.emitValueImpl(SRE, 4);
252}
253
255 size_t Offset = MCCVLines.size();
256 auto I = MCCVLineStartStop.insert(
257 {LineEntry.getFunctionId(), {Offset, Offset + 1}});
258 if (!I.second)
259 I.first->second.second = Offset + 1;
260 MCCVLines.push_back(LineEntry);
261}
262
263std::vector<MCCVLoc>
265 std::vector<MCCVLoc> FilteredLines;
266 size_t LocBegin;
267 size_t LocEnd;
268 std::tie(LocBegin, LocEnd) = getLineExtentIncludingInlinees(FuncId);
269 if (LocBegin >= LocEnd) {
270 return FilteredLines;
271 }
272
273 MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(FuncId);
274 for (size_t Idx = LocBegin; Idx != LocEnd; ++Idx) {
275 unsigned LocationFuncId = MCCVLines[Idx].getFunctionId();
276 if (LocationFuncId == FuncId) {
277 // This was a .cv_loc directly for FuncId, so record it.
278 FilteredLines.push_back(MCCVLines[Idx]);
279 } else {
280 // Check if the current location is inlined in this function. If it is,
281 // synthesize a statement .cv_loc at the original inlined call site.
282 auto I = SiteInfo->InlinedAtMap.find(LocationFuncId);
283 if (I != SiteInfo->InlinedAtMap.end()) {
284 MCCVFunctionInfo::LineInfo &IA = I->second;
285 // Only add the location if it differs from the previous location.
286 // Large inlined calls will have many .cv_loc entries and we only need
287 // one line table entry in the parent function.
288 if (FilteredLines.empty() ||
289 FilteredLines.back().getFileNum() != IA.File ||
290 FilteredLines.back().getLine() != IA.Line ||
291 FilteredLines.back().getColumn() != IA.Col) {
292 FilteredLines.push_back(MCCVLoc(MCCVLines[Idx].getLabel(), FuncId,
293 IA.File, IA.Line, IA.Col, false,
294 false));
295 }
296 }
297 }
298 }
299 return FilteredLines;
300}
301
302std::pair<size_t, size_t> CodeViewContext::getLineExtent(unsigned FuncId) {
303 auto I = MCCVLineStartStop.find(FuncId);
304 // Return an empty extent if there are no cv_locs for this function id.
305 if (I == MCCVLineStartStop.end())
306 return {~0ULL, 0};
307 return I->second;
308}
309
310std::pair<size_t, size_t>
312 size_t LocBegin;
313 size_t LocEnd;
314 std::tie(LocBegin, LocEnd) = getLineExtent(FuncId);
315
316 // Include all child inline call sites in our extent.
317 MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(FuncId);
318 if (SiteInfo) {
319 for (auto &KV : SiteInfo->InlinedAtMap) {
320 unsigned ChildId = KV.first;
321 auto Extent = getLineExtent(ChildId);
322 LocBegin = std::min(LocBegin, Extent.first);
323 LocEnd = std::max(LocEnd, Extent.second);
324 }
325 }
326
327 return {LocBegin, LocEnd};
328}
329
331 if (R <= L)
332 return {};
333 if (L >= MCCVLines.size())
334 return {};
335 return ArrayRef(&MCCVLines[L], R - L);
336}
337
339 unsigned FuncId,
340 const MCSymbol *FuncBegin,
341 const MCSymbol *FuncEnd) {
342 MCContext &Ctx = OS.getContext();
343 MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin", false),
344 *LineEnd = Ctx.createTempSymbol("linetable_end", false);
345
347 OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4);
348 OS.emitLabel(LineBegin);
349 OS.emitCOFFSecRel32(FuncBegin, /*Offset=*/0);
350 OS.emitCOFFSectionIndex(FuncBegin);
351
352 // Actual line info.
353 std::vector<MCCVLoc> Locs = getFunctionLineEntries(FuncId);
354 bool HaveColumns = any_of(Locs, [](const MCCVLoc &LineEntry) {
355 return LineEntry.getColumn() != 0;
356 });
357 OS.emitInt16(HaveColumns ? int(LF_HaveColumns) : 0);
358 OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4);
359
360 for (auto I = Locs.begin(), E = Locs.end(); I != E;) {
361 // Emit a file segment for the run of locations that share a file id.
362 unsigned CurFileNum = I->getFileNum();
363 auto FileSegEnd =
364 std::find_if(I, E, [CurFileNum](const MCCVLoc &Loc) {
365 return Loc.getFileNum() != CurFileNum;
366 });
367 unsigned EntryCount = FileSegEnd - I;
368 OS.AddComment("Segment for file '" +
369 Twine(StrTab[Files[CurFileNum - 1].StringTableOffset]) +
370 "' begins");
372 OS.emitInt32(EntryCount);
373 uint32_t SegmentSize = 12;
374 SegmentSize += 8 * EntryCount;
375 if (HaveColumns)
376 SegmentSize += 4 * EntryCount;
377 OS.emitInt32(SegmentSize);
378
379 for (auto J = I; J != FileSegEnd; ++J) {
380 OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4);
381 unsigned LineData = J->getLine();
382 if (J->isStmt())
383 LineData |= LineInfo::StatementFlag;
384 OS.emitInt32(LineData);
385 }
386 if (HaveColumns) {
387 for (auto J = I; J != FileSegEnd; ++J) {
388 OS.emitInt16(J->getColumn());
389 OS.emitInt16(0);
390 }
391 }
392 I = FileSegEnd;
393 }
394 OS.emitLabel(LineEnd);
395}
396
398 if (isUInt<7>(Data)) {
399 Buffer.push_back(Data);
400 return true;
401 }
402
403 if (isUInt<14>(Data)) {
404 Buffer.push_back((Data >> 8) | 0x80);
405 Buffer.push_back(Data & 0xff);
406 return true;
407 }
408
409 if (isUInt<29>(Data)) {
410 Buffer.push_back((Data >> 24) | 0xC0);
411 Buffer.push_back((Data >> 16) & 0xff);
412 Buffer.push_back((Data >> 8) & 0xff);
413 Buffer.push_back(Data & 0xff);
414 return true;
415 }
416
417 return false;
418}
419
421 SmallVectorImpl<char> &Buffer) {
422 return compressAnnotation(static_cast<uint32_t>(Annotation), Buffer);
423}
424
426 if (Data >> 31)
427 return ((-Data) << 1) | 1;
428 return Data << 1;
429}
430
432 unsigned PrimaryFunctionId,
433 unsigned SourceFileId,
434 unsigned SourceLineNum,
435 const MCSymbol *FnStartSym,
436 const MCSymbol *FnEndSym) {
437 // Create and insert a fragment into the current section that will be encoded
438 // later.
440 PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
441}
442
445 ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
446 StringRef FixedSizePortion) {
447 // Store `Ranges` and `FixedSizePortion` in the context, returning references,
448 // as MCCVDefRangeFragment does not own these objects.
449 FixedSizePortion = MCCtx->allocateString(FixedSizePortion);
450 auto &Saved = DefRangeStorage.emplace_back(Ranges.begin(), Ranges.end());
451 // Create and insert a fragment into the current section that will be encoded
452 // later.
453 OS.newSpecialFragment<MCCVDefRangeFragment>(Saved, FixedSizePortion);
454}
455
456static unsigned computeLabelDiff(const MCAssembler &Asm, const MCSymbol *Begin,
457 const MCSymbol *End) {
458 MCContext &Ctx = Asm.getContext();
459 const MCExpr *BeginRef = MCSymbolRefExpr::create(Begin, Ctx),
460 *EndRef = MCSymbolRefExpr::create(End, Ctx);
461 const MCExpr *AddrDelta =
462 MCBinaryExpr::create(MCBinaryExpr::Sub, EndRef, BeginRef, Ctx);
463 int64_t Result;
464 bool Success = AddrDelta->evaluateKnownAbsolute(Result, Asm);
465 assert(Success && "failed to evaluate label difference as absolute");
466 (void)Success;
467 assert(Result >= 0 && "negative label difference requested");
468 assert(Result < UINT_MAX && "label difference greater than 2GB");
469 return unsigned(Result);
470}
471
474 size_t LocBegin;
475 size_t LocEnd;
476 std::tie(LocBegin, LocEnd) = getLineExtentIncludingInlinees(Frag.SiteFuncId);
477
478 if (LocBegin >= LocEnd)
479 return;
480 ArrayRef<MCCVLoc> Locs = getLinesForExtent(LocBegin, LocEnd);
481 if (Locs.empty())
482 return;
483
484 // Check that the locations are all in the same section.
485#ifndef NDEBUG
486 const MCSection *FirstSec = &Locs.front().getLabel()->getSection();
487 for (const MCCVLoc &Loc : Locs) {
488 if (&Loc.getLabel()->getSection() != FirstSec) {
489 errs() << ".cv_loc " << Loc.getFunctionId() << ' ' << Loc.getFileNum()
490 << ' ' << Loc.getLine() << ' ' << Loc.getColumn()
491 << " is in the wrong section\n";
492 llvm_unreachable(".cv_loc crosses sections");
493 }
494 }
495#endif
496
497 // Make an artificial start location using the function start and the inlinee
498 // lines start location information. All deltas start relative to this
499 // location.
500 MCCVLoc StartLoc = Locs.front();
501 StartLoc.setLabel(Frag.getFnStartSym());
502 StartLoc.setFileNum(Frag.StartFileId);
503 StartLoc.setLine(Frag.StartLineNum);
504 bool HaveOpenRange = false;
505
506 const MCSymbol *LastLabel = Frag.getFnStartSym();
507 MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc;
508 LastSourceLoc.File = Frag.StartFileId;
509 LastSourceLoc.Line = Frag.StartLineNum;
510
511 MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId);
512
514 for (const MCCVLoc &Loc : Locs) {
515 // Exit early if our line table would produce an oversized InlineSiteSym
516 // record. Account for the ChangeCodeLength annotation emitted after the
517 // loop ends.
518 constexpr uint32_t InlineSiteSize = 12;
519 constexpr uint32_t AnnotationSize = 8;
520 size_t MaxBufferSize = MaxRecordLength - InlineSiteSize - AnnotationSize;
521 if (Buffer.size() >= MaxBufferSize)
522 break;
523
524 if (Loc.getFunctionId() == Frag.SiteFuncId) {
525 CurSourceLoc.File = Loc.getFileNum();
526 CurSourceLoc.Line = Loc.getLine();
527 } else {
528 auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId());
529 if (I != SiteInfo->InlinedAtMap.end()) {
530 // This .cv_loc is from a child inline call site. Use the source
531 // location of the inlined call site instead of the .cv_loc directive
532 // source location.
533 CurSourceLoc = I->second;
534 } else {
535 // We've hit a cv_loc not attributed to this inline call site. Use this
536 // label to end the PC range.
537 if (HaveOpenRange) {
538 unsigned Length = computeLabelDiff(Asm, LastLabel, Loc.getLabel());
540 compressAnnotation(Length, Buffer);
541 LastLabel = Loc.getLabel();
542 }
543 HaveOpenRange = false;
544 continue;
545 }
546 }
547
548 // Skip this .cv_loc if we have an open range and this isn't a meaningful
549 // source location update. The current table format does not support column
550 // info, so we can skip updates for those.
551 if (HaveOpenRange && CurSourceLoc.File == LastSourceLoc.File &&
552 CurSourceLoc.Line == LastSourceLoc.Line)
553 continue;
554
555 HaveOpenRange = true;
556
557 if (CurSourceLoc.File != LastSourceLoc.File) {
558 unsigned FileOffset = static_cast<const MCConstantExpr *>(
559 Files[CurSourceLoc.File - 1]
560 .ChecksumTableOffset->getVariableValue())
561 ->getValue();
563 compressAnnotation(FileOffset, Buffer);
564 }
565
566 int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line;
567 unsigned EncodedLineDelta = encodeSignedNumber(LineDelta);
568 unsigned CodeDelta = computeLabelDiff(Asm, LastLabel, Loc.getLabel());
569 if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) {
570 // The ChangeCodeOffsetAndLineOffset combination opcode is used when the
571 // encoded line delta uses 3 or fewer set bits and the code offset fits
572 // in one nibble.
573 unsigned Operand = (EncodedLineDelta << 4) | CodeDelta;
575 Buffer);
576 compressAnnotation(Operand, Buffer);
577 } else {
578 // Otherwise use the separate line and code deltas.
579 if (LineDelta != 0) {
581 compressAnnotation(EncodedLineDelta, Buffer);
582 }
584 compressAnnotation(CodeDelta, Buffer);
585 }
586
587 LastLabel = Loc.getLabel();
588 LastSourceLoc = CurSourceLoc;
589 }
590
591 assert(HaveOpenRange);
592
593 unsigned EndSymLength =
594 computeLabelDiff(Asm, LastLabel, Frag.getFnEndSym());
595 unsigned LocAfterLength = ~0U;
596 ArrayRef<MCCVLoc> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1);
597 if (!LocAfter.empty()) {
598 // Only try to compute this difference if we're in the same section.
599 const MCCVLoc &Loc = LocAfter[0];
600 if (&Loc.getLabel()->getSection() == &LastLabel->getSection())
601 LocAfterLength = computeLabelDiff(Asm, LastLabel, Loc.getLabel());
602 }
603
605 compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer);
606 Frag.setVarContents(Buffer);
607}
608
610 MCCVDefRangeFragment &Frag) {
611 MCContext &Ctx = Asm.getContext();
612 SmallVector<char, 0> Contents;
614 raw_svector_ostream OS(Contents);
615
616 // Compute all the sizes up front.
618 const MCSymbol *LastLabel = nullptr;
619 for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) {
620 unsigned GapSize =
621 LastLabel ? computeLabelDiff(Asm, LastLabel, Range.first) : 0;
622 unsigned RangeSize = computeLabelDiff(Asm, Range.first, Range.second);
623 GapAndRangeSizes.push_back({GapSize, RangeSize});
624 LastLabel = Range.second;
625 }
626
627 // Write down each range where the variable is defined.
628 for (size_t I = 0, E = Frag.getRanges().size(); I != E;) {
629 // If the range size of multiple consecutive ranges is under the max,
630 // combine the ranges and emit some gaps.
631 const MCSymbol *RangeBegin = Frag.getRanges()[I].first;
632 unsigned RangeSize = GapAndRangeSizes[I].second;
633 size_t J = I + 1;
634 for (; J != E; ++J) {
635 unsigned GapAndRangeSize = GapAndRangeSizes[J].first + GapAndRangeSizes[J].second;
636 if (RangeSize + GapAndRangeSize > MaxDefRange)
637 break;
638 RangeSize += GapAndRangeSize;
639 }
640 unsigned NumGaps = J - I - 1;
641
643
644 unsigned Bias = 0;
645 // We must split the range into chunks of MaxDefRange, this is a fundamental
646 // limitation of the file format.
647 do {
648 uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize);
649
650 const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(RangeBegin, Ctx);
651 const MCBinaryExpr *BE =
653
654 // Each record begins with a 2-byte number indicating how large the record
655 // is.
656 StringRef FixedSizePortion = Frag.getFixedSizePortion();
657 // Our record is a fixed sized prefix and a LocalVariableAddrRange that we
658 // are artificially constructing.
659 size_t RecordSize = FixedSizePortion.size() +
660 sizeof(LocalVariableAddrRange) + 4 * NumGaps;
661 // Write out the record size.
662 LEWriter.write<uint16_t>(RecordSize);
663 // Write out the fixed size prefix.
664 OS << FixedSizePortion;
665 // Make space for a fixup that will eventually have a section relative
666 // relocation pointing at the offset where the variable becomes live.
667 Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4));
668 LEWriter.write<uint32_t>(0); // Fixup for code start.
669 // Make space for a fixup that will record the section index for the code.
670 Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2));
671 LEWriter.write<uint16_t>(0); // Fixup for section index.
672 // Write down the range's extent.
673 LEWriter.write<uint16_t>(Chunk);
674
675 // Move on to the next range.
676 Bias += Chunk;
677 RangeSize -= Chunk;
678 } while (RangeSize > 0);
679
680 // Emit the gaps afterwards.
681 assert((NumGaps == 0 || Bias <= MaxDefRange) &&
682 "large ranges should not have gaps");
683 unsigned GapStartOffset = GapAndRangeSizes[I].second;
684 for (++I; I != J; ++I) {
685 unsigned GapSize, RangeSize;
686 assert(I < GapAndRangeSizes.size());
687 std::tie(GapSize, RangeSize) = GapAndRangeSizes[I];
688 LEWriter.write<uint16_t>(GapStartOffset);
689 LEWriter.write<uint16_t>(GapSize);
690 GapStartOffset += GapSize + RangeSize;
691 }
692 }
693
694 Frag.setVarContents(Contents);
695 assert(Fixups.size() < 256 && "Store fixups outside of MCFragment's VarFixup "
696 "storage if the number ever exceeds 256");
697 Frag.setVarFixups(Fixups);
698}
#define Success
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Fixup Statepoint Caller Saved
static unsigned computeLabelDiff(const MCAssembler &Asm, const MCSymbol *Begin, const MCSymbol *End)
static uint32_t encodeSignedNumber(uint32_t Data)
static bool compressAnnotation(uint32_t Data, SmallVectorImpl< char > &Buffer)
#define I(x, y, z)
Definition MD5.cpp:58
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
This file contains some templates that are useful if you are working with the STL at all.
This file contains some functions that are useful when dealing with strings.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:41
const T & front() const
front - Get the first element.
Definition ArrayRef.h:150
bool empty() const
empty - Check if the array is empty.
Definition ArrayRef.h:142
ArrayRef< MCCVLoc > getLinesForExtent(size_t L, size_t R)
std::pair< size_t, size_t > getLineExtent(unsigned FuncId)
void encodeInlineLineTable(const MCAssembler &Asm, MCCVInlineLineTableFragment &F)
Encodes the binary annotations once we have a layout.
void emitLineTableForFunction(MCObjectStreamer &OS, unsigned FuncId, const MCSymbol *FuncBegin, const MCSymbol *FuncEnd)
Emits a line table substream.
void emitFileChecksums(MCObjectStreamer &OS)
Emits the file checksum substream.
void recordCVLoc(MCContext &Ctx, const MCSymbol *Label, unsigned FunctionId, unsigned FileNo, unsigned Line, unsigned Column, bool PrologueEnd, bool IsStmt)
Saves the information from the currently parsed .cv_loc directive and sets CVLocSeen.
void emitDefRange(MCObjectStreamer &OS, ArrayRef< std::pair< const MCSymbol *, const MCSymbol * > > Ranges, StringRef FixedSizePortion)
bool addFile(MCStreamer &OS, unsigned FileNumber, StringRef Filename, ArrayRef< uint8_t > ChecksumBytes, uint8_t ChecksumKind)
MCCVFunctionInfo * getCVFunctionInfo(unsigned FuncId)
Retreive the function info if this is a valid function id, or nullptr.
bool recordFunctionId(unsigned FuncId)
Records the function id of a normal function.
void emitFileChecksumOffset(MCObjectStreamer &OS, unsigned FileNo)
Emits the offset into the checksum table of the given file number.
std::vector< MCCVLoc > getFunctionLineEntries(unsigned FuncId)
void addLineEntry(const MCCVLoc &LineEntry)
Add a line entry.
bool recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc, unsigned IAFile, unsigned IALine, unsigned IACol)
Records the function id of an inlined call site.
std::pair< size_t, size_t > getLineExtentIncludingInlinees(unsigned FuncId)
void emitInlineLineTableForFunction(MCObjectStreamer &OS, unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum, const MCSymbol *FnStartSym, const MCSymbol *FnEndSym)
void emitStringTable(MCObjectStreamer &OS)
Emits the string table substream.
bool isValidFileNumber(unsigned FileNumber) const
This is a valid number for use with .cv_loc if we've already seen a .cv_file for it.
void encodeDefRange(const MCAssembler &Asm, MCCVDefRangeFragment &F)
std::pair< StringRef, unsigned > addToStringTable(StringRef S)
Add something to the string table.
Binary assembler expressions.
Definition MCExpr.h:299
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:343
static LLVM_ABI const MCBinaryExpr * create(Opcode Op, const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.cpp:201
@ Sub
Subtraction.
Definition MCExpr.h:324
Fragment representing the .cv_def_range directive.
Definition MCSection.h:430
ArrayRef< std::pair< const MCSymbol *, const MCSymbol * > > getRanges() const
Definition MCSection.h:445
StringRef getFixedSizePortion() const
Definition MCSection.h:449
Fragment representing the binary annotations produced by the .cv_inline_linetable directive.
Definition MCSection.h:402
const MCSymbol * getFnStartSym() const
Definition MCSection.h:421
const MCSymbol * getFnEndSym() const
Definition MCSection.h:422
Instances of this class represent the information from a .cv_loc directive.
Definition MCCodeView.h:38
void setFileNum(unsigned fileNum)
Set the FileNum of this MCCVLoc.
Definition MCCodeView.h:79
void setLabel(const MCSymbol *L)
Definition MCCodeView.h:74
unsigned getColumn() const
Get the Column of this MCCVLoc.
Definition MCCodeView.h:69
unsigned getFunctionId() const
Definition MCCodeView.h:60
void setLine(unsigned line)
Set the Line of this MCCVLoc.
Definition MCCodeView.h:82
int64_t getValue() const
Definition MCExpr.h:171
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition MCExpr.cpp:212
Context object for machine code objects.
Definition MCContext.h:83
LLVM_ABI MCSymbol * createTempSymbol()
Create a temporary symbol with a unique name.
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
LLVM_ABI bool evaluateKnownAbsolute(int64_t &Res, const MCAssembler &Asm) const
Aggressive variant of evaluateAsRelocatable when relocations are unavailable (e.g.
Definition MCExpr.cpp:250
static MCFixup create(uint32_t Offset, const MCExpr *Value, MCFixupKind Kind, bool PCRel=false)
Consider bit fields if we need more flags.
Definition MCFixup.h:86
LLVM_ABI void setVarFixups(ArrayRef< MCFixup > Fixups)
Definition MCSection.cpp:87
LLVM_ABI void setVarContents(ArrayRef< char > Contents)
Definition MCSection.cpp:61
Streaming object file generation interface.
FT * newSpecialFragment(Args &&...args)
void emitValueToAlignment(Align Alignment, int64_t Fill=0, uint8_t FillLen=1, unsigned MaxBytesToEmit=0) override
Emit some number of copies of Value until the byte alignment ByteAlignment is reached.
void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override
Emit an assignment of Value to Symbol.
void emitBytes(StringRef Data) override
Emit the bytes in Data into the output.
void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc()) override
Emit a label for Symbol into the current section.
void emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc()) override
Emit the expression Value into the output as a native integer of the given Size bytes.
void emitCVFileChecksumOffsetDirective(unsigned FileNo) override
This implements the CodeView '.cv_filechecksumoffset' assembler directive.
void emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, unsigned Size) override
Emit the absolute difference between two symbols if possible.
Instances of this class represent a uniqued identifier for a section in the current translation unit.
Definition MCSection.h:496
Streaming machine code generation interface.
Definition MCStreamer.h:220
MCFragment * getCurrentFragment() const
Definition MCStreamer.h:432
MCContext & getContext() const
Definition MCStreamer.h:314
virtual void AddComment(const Twine &T, bool EOL=true)
Add a textual comment.
Definition MCStreamer.h:387
virtual void emitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset)
Emits a COFF section relative relocation.
void emitSymbolValue(const MCSymbol *Sym, unsigned Size, bool IsSectionRelative=false)
Special case of EmitValue that avoids the client having to pass in a MCExpr for MCSymbols.
virtual void emitCOFFSectionIndex(MCSymbol const *Symbol)
Emits a COFF section index.
void emitInt16(uint64_t Value)
Definition MCStreamer.h:749
void emitInt32(uint64_t Value)
Definition MCStreamer.h:750
void emitInt8(uint64_t Value)
Definition MCStreamer.h:748
Represent a reference to a symbol from inside an expression.
Definition MCExpr.h:190
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:214
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
MCSection & getSection() const
Get the section associated with a defined, non-absolute symbol.
Definition MCSymbol.h:251
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:151
constexpr size_t size() const
size - Get the string size.
Definition StringRef.h:154
A table of densely packed, null-terminated strings indexed by offset.
Definition StringTable.h:33
constexpr Iterator end() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
A raw_ostream that writes to an SmallVector or SmallString.
This class represents a function that is read from a sample profile.
Definition FunctionId.h:36
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:477
@ Length
Definition DWP.cpp:477
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1714
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:198
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
@ FK_SecRel_2
A two-byte section relative fixup.
Definition MCFixup.h:40
@ FK_SecRel_4
A four-byte section relative fixup.
Definition MCFixup.h:41
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:189
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:155
ArrayRef(const T &OneElt) -> ArrayRef< T >
StringRef toStringRef(bool B)
Construct a string ref from a boolean.
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
Information describing a function or inlined call site introduced by .cv_func_id or ....
Definition MCCodeView.h:98
unsigned ParentFuncIdPlusOne
If this represents an inlined call site, then ParentFuncIdPlusOne will be the parent function id plus...
Definition MCCodeView.h:104
DenseMap< unsigned, LineInfo > InlinedAtMap
Map from inlined call site id to the inlined at location to use for that call site.
Definition MCCodeView.h:124
Adapter to write values to a stream in a particular byte order.
void write(ArrayRef< value_type > Val)