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/MC/MCAsmLayout.h"
16 #include "llvm/ADT/STLExtras.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/MCContext.h"
21 #include "llvm/MC/MCObjectStreamer.h"
22 #include "llvm/MC/MCValue.h"
23 #include "llvm/Support/COFF.h"
24 #include "llvm/Support/EndianStream.h"
25 
26 using namespace llvm;
27 using namespace llvm::codeview;
28 
29 CodeViewContext::CodeViewContext() {}
30 
31 CodeViewContext::~CodeViewContext() {
32   // If someone inserted strings into the string table but never actually
33   // emitted them somewhere, clean up the fragment.
34   if (!InsertedStrTabFragment)
35     delete StrTabFragment;
36 }
37 
38 /// This is a valid number for use with .cv_loc if we've already seen a .cv_file
39 /// for it.
40 bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const {
41   unsigned Idx = FileNumber - 1;
42   if (Idx < Filenames.size())
43     return !Filenames[Idx].empty();
44   return false;
45 }
46 
47 bool CodeViewContext::addFile(unsigned FileNumber, StringRef Filename) {
48   assert(FileNumber > 0);
49   Filename = addToStringTable(Filename);
50   unsigned Idx = FileNumber - 1;
51   if (Idx >= Filenames.size())
52     Filenames.resize(Idx + 1);
53 
54   if (Filename.empty())
55     Filename = "<stdin>";
56 
57   if (!Filenames[Idx].empty())
58     return false;
59 
60   // FIXME: We should store the string table offset of the filename, rather than
61   // the filename itself for efficiency.
62   Filename = addToStringTable(Filename);
63 
64   Filenames[Idx] = Filename;
65   return true;
66 }
67 
68 bool CodeViewContext::recordFunctionId(unsigned FuncId) {
69   if (FuncId >= Functions.size())
70     Functions.resize(FuncId + 1);
71 
72   // Return false if this function info was already allocated.
73   if (!Functions[FuncId].isUnallocatedFunctionInfo())
74     return false;
75 
76   // Mark this as an allocated normal function, and leave the rest alone.
77   Functions[FuncId].ParentFuncIdPlusOne = MCCVFunctionInfo::FunctionSentinel;
78   return true;
79 }
80 
81 bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
82                                               unsigned IAFile, unsigned IALine,
83                                               unsigned IACol) {
84   if (FuncId >= Functions.size())
85     Functions.resize(FuncId + 1);
86 
87   // Return false if this function info was already allocated.
88   if (!Functions[FuncId].isUnallocatedFunctionInfo())
89     return false;
90 
91   MCCVFunctionInfo::LineInfo InlinedAt;
92   InlinedAt.File = IAFile;
93   InlinedAt.Line = IALine;
94   InlinedAt.Col = IACol;
95 
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 
101   // Walk up the call chain adding this function id to the InlinedAtMap of all
102   // transitive callers until we hit a real function.
103   while (Info->isInlinedCallSite()) {
104     InlinedAt = Info->InlinedAt;
105     Info = getCVFunctionInfo(Info->getParentFuncId());
106     Info->InlinedAtMap[FuncId] = InlinedAt;
107   }
108 
109   return true;
110 }
111 
112 MCDataFragment *CodeViewContext::getStringTableFragment() {
113   if (!StrTabFragment) {
114     StrTabFragment = new MCDataFragment();
115     // Start a new string table out with a null byte.
116     StrTabFragment->getContents().push_back('\0');
117   }
118   return StrTabFragment;
119 }
120 
121 StringRef CodeViewContext::addToStringTable(StringRef S) {
122   SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents();
123   auto Insertion =
124       StringTable.insert(std::make_pair(S, unsigned(Contents.size())));
125   // Return the string from the table, since it is stable.
126   S = Insertion.first->first();
127   if (Insertion.second) {
128     // The string map key is always null terminated.
129     Contents.append(S.begin(), S.end() + 1);
130   }
131   return S;
132 }
133 
134 unsigned CodeViewContext::getStringTableOffset(StringRef S) {
135   // A string table offset of zero is always the empty string.
136   if (S.empty())
137     return 0;
138   auto I = StringTable.find(S);
139   assert(I != StringTable.end());
140   return I->second;
141 }
142 
143 void CodeViewContext::emitStringTable(MCObjectStreamer &OS) {
144   MCContext &Ctx = OS.getContext();
145   MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin", false),
146            *StringEnd = Ctx.createTempSymbol("strtab_end", false);
147 
148   OS.EmitIntValue(unsigned(ModuleSubstreamKind::StringTable), 4);
149   OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4);
150   OS.EmitLabel(StringBegin);
151 
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 
160   OS.EmitValueToAlignment(4, 0);
161 
162   OS.EmitLabel(StringEnd);
163 }
164 
165 void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) {
166   // Do nothing if there are no file checksums. Microsoft's linker rejects empty
167   // CodeView substreams.
168   if (Filenames.empty())
169     return;
170 
171   MCContext &Ctx = OS.getContext();
172   MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin", false),
173            *FileEnd = Ctx.createTempSymbol("filechecksums_end", false);
174 
175   OS.EmitIntValue(unsigned(ModuleSubstreamKind::FileChecksums), 4);
176   OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4);
177   OS.EmitLabel(FileBegin);
178 
179   // Emit an array of FileChecksum entries. We index into this table using the
180   // user-provided file number. Each entry is currently 8 bytes, as we don't
181   // emit checksums.
182   for (StringRef Filename : Filenames) {
183     OS.EmitIntValue(getStringTableOffset(Filename), 4);
184     // Zero the next two fields and align back to 4 bytes. This indicates that
185     // no checksum is present.
186     OS.EmitIntValue(0, 4);
187   }
188 
189   OS.EmitLabel(FileEnd);
190 }
191 
192 void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS,
193                                                unsigned FuncId,
194                                                const MCSymbol *FuncBegin,
195                                                const MCSymbol *FuncEnd) {
196   MCContext &Ctx = OS.getContext();
197   MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin", false),
198            *LineEnd = Ctx.createTempSymbol("linetable_end", false);
199 
200   OS.EmitIntValue(unsigned(ModuleSubstreamKind::Lines), 4);
201   OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4);
202   OS.EmitLabel(LineBegin);
203   OS.EmitCOFFSecRel32(FuncBegin);
204   OS.EmitCOFFSectionIndex(FuncBegin);
205 
206   // Actual line info.
207   std::vector<MCCVLineEntry> Locs = getFunctionLineEntries(FuncId);
208   bool HaveColumns = any_of(Locs, [](const MCCVLineEntry &LineEntry) {
209     return LineEntry.getColumn() != 0;
210   });
211   OS.EmitIntValue(HaveColumns ? int(LineFlags::HaveColumns) : 0, 2);
212   OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4);
213 
214   for (auto I = Locs.begin(), E = Locs.end(); I != E;) {
215     // Emit a file segment for the run of locations that share a file id.
216     unsigned CurFileNum = I->getFileNum();
217     auto FileSegEnd =
218         std::find_if(I, E, [CurFileNum](const MCCVLineEntry &Loc) {
219           return Loc.getFileNum() != CurFileNum;
220         });
221     unsigned EntryCount = FileSegEnd - I;
222     OS.AddComment("Segment for file '" + Twine(Filenames[CurFileNum - 1]) +
223                   "' begins");
224     OS.EmitIntValue(8 * (CurFileNum - 1), 4);
225     OS.EmitIntValue(EntryCount, 4);
226     uint32_t SegmentSize = 12;
227     SegmentSize += 8 * EntryCount;
228     if (HaveColumns)
229       SegmentSize += 4 * EntryCount;
230     OS.EmitIntValue(SegmentSize, 4);
231 
232     for (auto J = I; J != FileSegEnd; ++J) {
233       OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4);
234       unsigned LineData = J->getLine();
235       if (J->isStmt())
236         LineData |= LineInfo::StatementFlag;
237       OS.EmitIntValue(LineData, 4);
238     }
239     if (HaveColumns) {
240       for (auto J = I; J != FileSegEnd; ++J) {
241         OS.EmitIntValue(J->getColumn(), 2);
242         OS.EmitIntValue(0, 2);
243       }
244     }
245     I = FileSegEnd;
246   }
247   OS.EmitLabel(LineEnd);
248 }
249 
250 static bool compressAnnotation(uint32_t Data, SmallVectorImpl<char> &Buffer) {
251   if (isUInt<7>(Data)) {
252     Buffer.push_back(Data);
253     return true;
254   }
255 
256   if (isUInt<14>(Data)) {
257     Buffer.push_back((Data >> 8) | 0x80);
258     Buffer.push_back(Data & 0xff);
259     return true;
260   }
261 
262   if (isUInt<29>(Data)) {
263     Buffer.push_back((Data >> 24) | 0xC0);
264     Buffer.push_back((Data >> 16) & 0xff);
265     Buffer.push_back((Data >> 8) & 0xff);
266     Buffer.push_back(Data & 0xff);
267     return true;
268   }
269 
270   return false;
271 }
272 
273 static bool compressAnnotation(BinaryAnnotationsOpCode Annotation,
274                                SmallVectorImpl<char> &Buffer) {
275   return compressAnnotation(static_cast<uint32_t>(Annotation), Buffer);
276 }
277 
278 static uint32_t encodeSignedNumber(uint32_t Data) {
279   if (Data >> 31)
280     return ((-Data) << 1) | 1;
281   return Data << 1;
282 }
283 
284 void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS,
285                                                      unsigned PrimaryFunctionId,
286                                                      unsigned SourceFileId,
287                                                      unsigned SourceLineNum,
288                                                      const MCSymbol *FnStartSym,
289                                                      const MCSymbol *FnEndSym) {
290   // Create and insert a fragment into the current section that will be encoded
291   // later.
292   new MCCVInlineLineTableFragment(PrimaryFunctionId, SourceFileId,
293                                   SourceLineNum, FnStartSym, FnEndSym,
294                                   OS.getCurrentSectionOnly());
295 }
296 
297 void CodeViewContext::emitDefRange(
298     MCObjectStreamer &OS,
299     ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
300     StringRef FixedSizePortion) {
301   // Create and insert a fragment into the current section that will be encoded
302   // later.
303   new MCCVDefRangeFragment(Ranges, FixedSizePortion,
304                            OS.getCurrentSectionOnly());
305 }
306 
307 static unsigned computeLabelDiff(MCAsmLayout &Layout, const MCSymbol *Begin,
308                                  const MCSymbol *End) {
309   MCContext &Ctx = Layout.getAssembler().getContext();
310   MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
311   const MCExpr *BeginRef = MCSymbolRefExpr::create(Begin, Variant, Ctx),
312                *EndRef = MCSymbolRefExpr::create(End, Variant, Ctx);
313   const MCExpr *AddrDelta =
314       MCBinaryExpr::create(MCBinaryExpr::Sub, EndRef, BeginRef, Ctx);
315   int64_t Result;
316   bool Success = AddrDelta->evaluateKnownAbsolute(Result, Layout);
317   assert(Success && "failed to evaluate label difference as absolute");
318   (void)Success;
319   assert(Result >= 0 && "negative label difference requested");
320   assert(Result < UINT_MAX && "label difference greater than 2GB");
321   return unsigned(Result);
322 }
323 
324 void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
325                                             MCCVInlineLineTableFragment &Frag) {
326   size_t LocBegin;
327   size_t LocEnd;
328   std::tie(LocBegin, LocEnd) = getLineExtent(Frag.SiteFuncId);
329 
330   // Include all child inline call sites in our .cv_loc extent.
331   MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId);
332   for (auto &KV : SiteInfo->InlinedAtMap) {
333     unsigned ChildId = KV.first;
334     auto Extent = getLineExtent(ChildId);
335     LocBegin = std::min(LocBegin, Extent.first);
336     LocEnd = std::max(LocEnd, Extent.second);
337   }
338 
339   if (LocBegin >= LocEnd)
340     return;
341   ArrayRef<MCCVLineEntry> Locs = getLinesForExtent(LocBegin, LocEnd);
342   if (Locs.empty())
343     return;
344 
345   // Make an artificial start location using the function start and the inlinee
346   // lines start location information. All deltas start relative to this
347   // location.
348   MCCVLineEntry StartLoc(Frag.getFnStartSym(), MCCVLoc(Locs.front()));
349   StartLoc.setFileNum(Frag.StartFileId);
350   StartLoc.setLine(Frag.StartLineNum);
351   bool HaveOpenRange = false;
352 
353   const MCSymbol *LastLabel = Frag.getFnStartSym();
354   MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc;
355   LastSourceLoc.File = Frag.StartFileId;
356   LastSourceLoc.Line = Frag.StartLineNum;
357 
358   SmallVectorImpl<char> &Buffer = Frag.getContents();
359   Buffer.clear(); // Clear old contents if we went through relaxation.
360   for (const MCCVLineEntry &Loc : Locs) {
361     if (Loc.getFunctionId() == Frag.SiteFuncId) {
362       CurSourceLoc.File = Loc.getFileNum();
363       CurSourceLoc.Line = Loc.getLine();
364     } else {
365       auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId());
366       if (I != SiteInfo->InlinedAtMap.end()) {
367         // This .cv_loc is from a child inline call site. Use the source
368         // location of the inlined call site instead of the .cv_loc directive
369         // source location.
370         CurSourceLoc = I->second;
371       } else {
372         // We've hit a cv_loc not attributed to this inline call site. Use this
373         // label to end the PC range.
374         if (HaveOpenRange) {
375           unsigned Length = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
376           compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
377           compressAnnotation(Length, Buffer);
378           LastLabel = Loc.getLabel();
379         }
380         HaveOpenRange = false;
381         continue;
382       }
383     }
384 
385     // Skip this .cv_loc if we have an open range and this isn't a meaningful
386     // source location update. The current table format does not support column
387     // info, so we can skip updates for those.
388     if (HaveOpenRange && CurSourceLoc.File == LastSourceLoc.File &&
389         CurSourceLoc.Line == LastSourceLoc.Line)
390       continue;
391 
392     HaveOpenRange = true;
393 
394     if (CurSourceLoc.File != LastSourceLoc.File) {
395       // File ids are 1 based, and each file checksum table entry is 8 bytes
396       // long. See emitFileChecksums above.
397       unsigned FileOffset = 8 * (CurSourceLoc.File - 1);
398       compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer);
399       compressAnnotation(FileOffset, Buffer);
400     }
401 
402     int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line;
403     unsigned EncodedLineDelta = encodeSignedNumber(LineDelta);
404     unsigned CodeDelta = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
405     if (CodeDelta == 0 && LineDelta != 0) {
406       compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
407       compressAnnotation(EncodedLineDelta, Buffer);
408     } else if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) {
409       // The ChangeCodeOffsetAndLineOffset combination opcode is used when the
410       // encoded line delta uses 3 or fewer set bits and the code offset fits
411       // in one nibble.
412       unsigned Operand = (EncodedLineDelta << 4) | CodeDelta;
413       compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset,
414                          Buffer);
415       compressAnnotation(Operand, Buffer);
416     } else {
417       // Otherwise use the separate line and code deltas.
418       if (LineDelta != 0) {
419         compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
420         compressAnnotation(EncodedLineDelta, Buffer);
421       }
422       compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffset, Buffer);
423       compressAnnotation(CodeDelta, Buffer);
424     }
425 
426     LastLabel = Loc.getLabel();
427     LastSourceLoc = CurSourceLoc;
428   }
429 
430   assert(HaveOpenRange);
431 
432   unsigned EndSymLength =
433       computeLabelDiff(Layout, LastLabel, Frag.getFnEndSym());
434   unsigned LocAfterLength = ~0U;
435   ArrayRef<MCCVLineEntry> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1);
436   if (!LocAfter.empty()) {
437     // Only try to compute this difference if we're in the same section.
438     const MCCVLineEntry &Loc = LocAfter[0];
439     if (&Loc.getLabel()->getSection(false) == &LastLabel->getSection(false))
440       LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
441   }
442 
443   compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
444   compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer);
445 }
446 
447 void CodeViewContext::encodeDefRange(MCAsmLayout &Layout,
448                                      MCCVDefRangeFragment &Frag) {
449   MCContext &Ctx = Layout.getAssembler().getContext();
450   SmallVectorImpl<char> &Contents = Frag.getContents();
451   Contents.clear();
452   SmallVectorImpl<MCFixup> &Fixups = Frag.getFixups();
453   Fixups.clear();
454   raw_svector_ostream OS(Contents);
455 
456   // Write down each range where the variable is defined.
457   for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) {
458     unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second);
459     unsigned Bias = 0;
460     // We must split the range into chunks of MaxDefRange, this is a fundamental
461     // limitation of the file format.
462     do {
463       uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize);
464 
465       const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Range.first, Ctx);
466       const MCBinaryExpr *BE =
467           MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx);
468       MCValue Res;
469       BE->evaluateAsRelocatable(Res, &Layout, /*Fixup=*/nullptr);
470 
471       // Each record begins with a 2-byte number indicating how large the record
472       // is.
473       StringRef FixedSizePortion = Frag.getFixedSizePortion();
474       // Our record is a fixed sized prefix and a LocalVariableAddrRange that we
475       // are artificially constructing.
476       size_t RecordSize =
477           FixedSizePortion.size() + sizeof(LocalVariableAddrRange);
478       // Write out the recrod size.
479       support::endian::Writer<support::little>(OS).write<uint16_t>(RecordSize);
480       // Write out the fixed size prefix.
481       OS << FixedSizePortion;
482       // Make space for a fixup that will eventually have a section relative
483       // relocation pointing at the offset where the variable becomes live.
484       Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4));
485       Contents.resize(Contents.size() + 4); // Fixup for code start.
486       // Make space for a fixup that will record the section index for the code.
487       Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2));
488       Contents.resize(Contents.size() + 2); // Fixup for section index.
489       // Write down the range's extent.
490       support::endian::Writer<support::little>(OS).write<uint16_t>(Chunk);
491 
492       // Move on to the next range.
493       Bias += Chunk;
494       RangeSize -= Chunk;
495     } while (RangeSize > 0);
496   }
497 }
498 
499 //
500 // This is called when an instruction is assembled into the specified section
501 // and if there is information from the last .cv_loc directive that has yet to have
502 // a line entry made for it is made.
503 //
504 void MCCVLineEntry::Make(MCObjectStreamer *MCOS) {
505   CodeViewContext &CVC = MCOS->getContext().getCVContext();
506   if (!CVC.getCVLocSeen())
507     return;
508 
509   // Create a symbol at in the current section for use in the line entry.
510   MCSymbol *LineSym = MCOS->getContext().createTempSymbol();
511   // Set the value of the symbol to use for the MCCVLineEntry.
512   MCOS->EmitLabel(LineSym);
513 
514   // Get the current .loc info saved in the context.
515   const MCCVLoc &CVLoc = CVC.getCurrentCVLoc();
516 
517   // Create a (local) line entry with the symbol and the current .loc info.
518   MCCVLineEntry LineEntry(LineSym, CVLoc);
519 
520   // clear CVLocSeen saying the current .loc info is now used.
521   CVC.clearCVLocSeen();
522 
523   // Add the line entry to this section's entries.
524   CVC.addLineEntry(LineEntry);
525 }
526