MCCodeView.cpp 25 KB

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