MCCodeView.cpp 25 KB

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