WinCodeViewLineTables.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. //===-- llvm/lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp --*- 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. // This file contains support for writing line tables info into COFF files.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "WinCodeViewLineTables.h"
  14. #include "llvm/MC/MCExpr.h"
  15. #include "llvm/MC/MCSymbol.h"
  16. #include "llvm/Support/COFF.h"
  17. namespace llvm {
  18. StringRef WinCodeViewLineTables::getFullFilepath(const MDNode *S) {
  19. assert(S);
  20. assert((isa<MDCompileUnit>(S) || isa<MDFile>(S) || isa<MDSubprogram>(S) ||
  21. isa<MDLexicalBlockBase>(S)) &&
  22. "Unexpected scope info");
  23. DIScope Scope = cast<MDScope>(S);
  24. StringRef Dir = Scope.getDirectory(),
  25. Filename = Scope.getFilename();
  26. char *&Result = DirAndFilenameToFilepathMap[std::make_pair(Dir, Filename)];
  27. if (Result)
  28. return Result;
  29. // Clang emits directory and relative filename info into the IR, but CodeView
  30. // operates on full paths. We could change Clang to emit full paths too, but
  31. // that would increase the IR size and probably not needed for other users.
  32. // For now, just concatenate and canonicalize the path here.
  33. std::string Filepath;
  34. if (Filename.find(':') == 1)
  35. Filepath = Filename;
  36. else
  37. Filepath = (Dir + "\\" + Filename).str();
  38. // Canonicalize the path. We have to do it textually because we may no longer
  39. // have access the file in the filesystem.
  40. // First, replace all slashes with backslashes.
  41. std::replace(Filepath.begin(), Filepath.end(), '/', '\\');
  42. // Remove all "\.\" with "\".
  43. size_t Cursor = 0;
  44. while ((Cursor = Filepath.find("\\.\\", Cursor)) != std::string::npos)
  45. Filepath.erase(Cursor, 2);
  46. // Replace all "\XXX\..\" with "\". Don't try too hard though as the original
  47. // path should be well-formatted, e.g. start with a drive letter, etc.
  48. Cursor = 0;
  49. while ((Cursor = Filepath.find("\\..\\", Cursor)) != std::string::npos) {
  50. // Something's wrong if the path starts with "\..\", abort.
  51. if (Cursor == 0)
  52. break;
  53. size_t PrevSlash = Filepath.rfind('\\', Cursor - 1);
  54. if (PrevSlash == std::string::npos)
  55. // Something's wrong, abort.
  56. break;
  57. Filepath.erase(PrevSlash, Cursor + 3 - PrevSlash);
  58. // The next ".." might be following the one we've just erased.
  59. Cursor = PrevSlash;
  60. }
  61. // Remove all duplicate backslashes.
  62. Cursor = 0;
  63. while ((Cursor = Filepath.find("\\\\", Cursor)) != std::string::npos)
  64. Filepath.erase(Cursor, 1);
  65. Result = strdup(Filepath.c_str());
  66. return StringRef(Result);
  67. }
  68. void WinCodeViewLineTables::maybeRecordLocation(DebugLoc DL,
  69. const MachineFunction *MF) {
  70. const MDNode *Scope = DL.getScope();
  71. if (!Scope)
  72. return;
  73. StringRef Filename = getFullFilepath(Scope);
  74. // Skip this instruction if it has the same file:line as the previous one.
  75. assert(CurFn);
  76. if (!CurFn->Instrs.empty()) {
  77. const InstrInfoTy &LastInstr = InstrInfo[CurFn->Instrs.back()];
  78. if (LastInstr.Filename == Filename && LastInstr.LineNumber == DL.getLine())
  79. return;
  80. }
  81. FileNameRegistry.add(Filename);
  82. MCSymbol *MCL = Asm->MMI->getContext().CreateTempSymbol();
  83. Asm->OutStreamer.EmitLabel(MCL);
  84. CurFn->Instrs.push_back(MCL);
  85. InstrInfo[MCL] = InstrInfoTy(Filename, DL.getLine());
  86. }
  87. WinCodeViewLineTables::WinCodeViewLineTables(AsmPrinter *AP)
  88. : Asm(nullptr), CurFn(nullptr) {
  89. MachineModuleInfo *MMI = AP->MMI;
  90. // If module doesn't have named metadata anchors or COFF debug section
  91. // is not available, skip any debug info related stuff.
  92. if (!MMI->getModule()->getNamedMetadata("llvm.dbg.cu") ||
  93. !AP->getObjFileLowering().getCOFFDebugSymbolsSection())
  94. return;
  95. // Tell MMI that we have debug info.
  96. MMI->setDebugInfoAvailability(true);
  97. Asm = AP;
  98. }
  99. void WinCodeViewLineTables::endModule() {
  100. if (FnDebugInfo.empty())
  101. return;
  102. assert(Asm != nullptr);
  103. Asm->OutStreamer.SwitchSection(
  104. Asm->getObjFileLowering().getCOFFDebugSymbolsSection());
  105. Asm->EmitInt32(COFF::DEBUG_SECTION_MAGIC);
  106. // The COFF .debug$S section consists of several subsections, each starting
  107. // with a 4-byte control code (e.g. 0xF1, 0xF2, etc) and then a 4-byte length
  108. // of the payload followed by the payload itself. The subsections are 4-byte
  109. // aligned.
  110. // Emit per-function debug information. This code is extracted into a
  111. // separate function for readability.
  112. for (size_t I = 0, E = VisitedFunctions.size(); I != E; ++I)
  113. emitDebugInfoForFunction(VisitedFunctions[I]);
  114. // This subsection holds a file index to offset in string table table.
  115. Asm->OutStreamer.AddComment("File index to string table offset subsection");
  116. Asm->EmitInt32(COFF::DEBUG_INDEX_SUBSECTION);
  117. size_t NumFilenames = FileNameRegistry.Infos.size();
  118. Asm->EmitInt32(8 * NumFilenames);
  119. for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) {
  120. StringRef Filename = FileNameRegistry.Filenames[I];
  121. // For each unique filename, just write its offset in the string table.
  122. Asm->EmitInt32(FileNameRegistry.Infos[Filename].StartOffset);
  123. // The function name offset is not followed by any additional data.
  124. Asm->EmitInt32(0);
  125. }
  126. // This subsection holds the string table.
  127. Asm->OutStreamer.AddComment("String table");
  128. Asm->EmitInt32(COFF::DEBUG_STRING_TABLE_SUBSECTION);
  129. Asm->EmitInt32(FileNameRegistry.LastOffset);
  130. // The payload starts with a null character.
  131. Asm->EmitInt8(0);
  132. for (size_t I = 0, E = FileNameRegistry.Filenames.size(); I != E; ++I) {
  133. // Just emit unique filenames one by one, separated by a null character.
  134. Asm->OutStreamer.EmitBytes(FileNameRegistry.Filenames[I]);
  135. Asm->EmitInt8(0);
  136. }
  137. // No more subsections. Fill with zeros to align the end of the section by 4.
  138. Asm->OutStreamer.EmitFill((-FileNameRegistry.LastOffset) % 4, 0);
  139. clear();
  140. }
  141. static void EmitLabelDiff(MCStreamer &Streamer,
  142. const MCSymbol *From, const MCSymbol *To,
  143. unsigned int Size = 4) {
  144. MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
  145. MCContext &Context = Streamer.getContext();
  146. const MCExpr *FromRef = MCSymbolRefExpr::Create(From, Variant, Context),
  147. *ToRef = MCSymbolRefExpr::Create(To, Variant, Context);
  148. const MCExpr *AddrDelta =
  149. MCBinaryExpr::Create(MCBinaryExpr::Sub, ToRef, FromRef, Context);
  150. Streamer.EmitValue(AddrDelta, Size);
  151. }
  152. void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) {
  153. // For each function there is a separate subsection
  154. // which holds the PC to file:line table.
  155. const MCSymbol *Fn = Asm->getSymbol(GV);
  156. assert(Fn);
  157. const FunctionInfo &FI = FnDebugInfo[GV];
  158. if (FI.Instrs.empty())
  159. return;
  160. assert(FI.End && "Don't know where the function ends?");
  161. StringRef GVName = GV->getName();
  162. StringRef FuncName;
  163. if (DISubprogram SP = getDISubprogram(GV))
  164. FuncName = SP->getDisplayName();
  165. // FIXME Clang currently sets DisplayName to "bar" for a C++
  166. // "namespace_foo::bar" function, see PR21528. Luckily, dbghelp.dll is trying
  167. // to demangle display names anyways, so let's just put a mangled name into
  168. // the symbols subsection until Clang gives us what we need.
  169. if (GVName.startswith("\01?"))
  170. FuncName = GVName.substr(1);
  171. // Emit a symbol subsection, required by VS2012+ to find function boundaries.
  172. MCSymbol *SymbolsBegin = Asm->MMI->getContext().CreateTempSymbol(),
  173. *SymbolsEnd = Asm->MMI->getContext().CreateTempSymbol();
  174. Asm->OutStreamer.AddComment("Symbol subsection for " + Twine(FuncName));
  175. Asm->EmitInt32(COFF::DEBUG_SYMBOL_SUBSECTION);
  176. EmitLabelDiff(Asm->OutStreamer, SymbolsBegin, SymbolsEnd);
  177. Asm->OutStreamer.EmitLabel(SymbolsBegin);
  178. {
  179. MCSymbol *ProcSegmentBegin = Asm->MMI->getContext().CreateTempSymbol(),
  180. *ProcSegmentEnd = Asm->MMI->getContext().CreateTempSymbol();
  181. EmitLabelDiff(Asm->OutStreamer, ProcSegmentBegin, ProcSegmentEnd, 2);
  182. Asm->OutStreamer.EmitLabel(ProcSegmentBegin);
  183. Asm->EmitInt16(COFF::DEBUG_SYMBOL_TYPE_PROC_START);
  184. // Some bytes of this segment don't seem to be required for basic debugging,
  185. // so just fill them with zeroes.
  186. Asm->OutStreamer.EmitFill(12, 0);
  187. // This is the important bit that tells the debugger where the function
  188. // code is located and what's its size:
  189. EmitLabelDiff(Asm->OutStreamer, Fn, FI.End);
  190. Asm->OutStreamer.EmitFill(12, 0);
  191. Asm->OutStreamer.EmitCOFFSecRel32(Fn);
  192. Asm->OutStreamer.EmitCOFFSectionIndex(Fn);
  193. Asm->EmitInt8(0);
  194. // Emit the function display name as a null-terminated string.
  195. Asm->OutStreamer.EmitBytes(FuncName);
  196. Asm->EmitInt8(0);
  197. Asm->OutStreamer.EmitLabel(ProcSegmentEnd);
  198. // We're done with this function.
  199. Asm->EmitInt16(0x0002);
  200. Asm->EmitInt16(COFF::DEBUG_SYMBOL_TYPE_PROC_END);
  201. }
  202. Asm->OutStreamer.EmitLabel(SymbolsEnd);
  203. // Every subsection must be aligned to a 4-byte boundary.
  204. Asm->OutStreamer.EmitFill((-FuncName.size()) % 4, 0);
  205. // PCs/Instructions are grouped into segments sharing the same filename.
  206. // Pre-calculate the lengths (in instructions) of these segments and store
  207. // them in a map for convenience. Each index in the map is the sequential
  208. // number of the respective instruction that starts a new segment.
  209. DenseMap<size_t, size_t> FilenameSegmentLengths;
  210. size_t LastSegmentEnd = 0;
  211. StringRef PrevFilename = InstrInfo[FI.Instrs[0]].Filename;
  212. for (size_t J = 1, F = FI.Instrs.size(); J != F; ++J) {
  213. if (PrevFilename == InstrInfo[FI.Instrs[J]].Filename)
  214. continue;
  215. FilenameSegmentLengths[LastSegmentEnd] = J - LastSegmentEnd;
  216. LastSegmentEnd = J;
  217. PrevFilename = InstrInfo[FI.Instrs[J]].Filename;
  218. }
  219. FilenameSegmentLengths[LastSegmentEnd] = FI.Instrs.size() - LastSegmentEnd;
  220. // Emit a line table subsection, requred to do PC-to-file:line lookup.
  221. Asm->OutStreamer.AddComment("Line table subsection for " + Twine(FuncName));
  222. Asm->EmitInt32(COFF::DEBUG_LINE_TABLE_SUBSECTION);
  223. MCSymbol *LineTableBegin = Asm->MMI->getContext().CreateTempSymbol(),
  224. *LineTableEnd = Asm->MMI->getContext().CreateTempSymbol();
  225. EmitLabelDiff(Asm->OutStreamer, LineTableBegin, LineTableEnd);
  226. Asm->OutStreamer.EmitLabel(LineTableBegin);
  227. // Identify the function this subsection is for.
  228. Asm->OutStreamer.EmitCOFFSecRel32(Fn);
  229. Asm->OutStreamer.EmitCOFFSectionIndex(Fn);
  230. // Insert padding after a 16-bit section index.
  231. Asm->EmitInt16(0);
  232. // Length of the function's code, in bytes.
  233. EmitLabelDiff(Asm->OutStreamer, Fn, FI.End);
  234. // PC-to-linenumber lookup table:
  235. MCSymbol *FileSegmentEnd = nullptr;
  236. for (size_t J = 0, F = FI.Instrs.size(); J != F; ++J) {
  237. MCSymbol *Instr = FI.Instrs[J];
  238. assert(InstrInfo.count(Instr));
  239. if (FilenameSegmentLengths.count(J)) {
  240. // We came to a beginning of a new filename segment.
  241. if (FileSegmentEnd)
  242. Asm->OutStreamer.EmitLabel(FileSegmentEnd);
  243. StringRef CurFilename = InstrInfo[FI.Instrs[J]].Filename;
  244. assert(FileNameRegistry.Infos.count(CurFilename));
  245. size_t IndexInStringTable =
  246. FileNameRegistry.Infos[CurFilename].FilenameID;
  247. // Each segment starts with the offset of the filename
  248. // in the string table.
  249. Asm->OutStreamer.AddComment(
  250. "Segment for file '" + Twine(CurFilename) + "' begins");
  251. MCSymbol *FileSegmentBegin = Asm->MMI->getContext().CreateTempSymbol();
  252. Asm->OutStreamer.EmitLabel(FileSegmentBegin);
  253. Asm->EmitInt32(8 * IndexInStringTable);
  254. // Number of PC records in the lookup table.
  255. size_t SegmentLength = FilenameSegmentLengths[J];
  256. Asm->EmitInt32(SegmentLength);
  257. // Full size of the segment for this filename, including the prev two
  258. // records.
  259. FileSegmentEnd = Asm->MMI->getContext().CreateTempSymbol();
  260. EmitLabelDiff(Asm->OutStreamer, FileSegmentBegin, FileSegmentEnd);
  261. }
  262. // The first PC with the given linenumber and the linenumber itself.
  263. EmitLabelDiff(Asm->OutStreamer, Fn, Instr);
  264. Asm->EmitInt32(InstrInfo[Instr].LineNumber);
  265. }
  266. if (FileSegmentEnd)
  267. Asm->OutStreamer.EmitLabel(FileSegmentEnd);
  268. Asm->OutStreamer.EmitLabel(LineTableEnd);
  269. }
  270. void WinCodeViewLineTables::beginFunction(const MachineFunction *MF) {
  271. assert(!CurFn && "Can't process two functions at once!");
  272. if (!Asm || !Asm->MMI->hasDebugInfo())
  273. return;
  274. const Function *GV = MF->getFunction();
  275. assert(FnDebugInfo.count(GV) == false);
  276. VisitedFunctions.push_back(GV);
  277. CurFn = &FnDebugInfo[GV];
  278. // Find the end of the function prolog.
  279. // FIXME: is there a simpler a way to do this? Can we just search
  280. // for the first instruction of the function, not the last of the prolog?
  281. DebugLoc PrologEndLoc;
  282. bool EmptyPrologue = true;
  283. for (const auto &MBB : *MF) {
  284. if (PrologEndLoc)
  285. break;
  286. for (const auto &MI : MBB) {
  287. if (MI.isDebugValue())
  288. continue;
  289. // First known non-DBG_VALUE and non-frame setup location marks
  290. // the beginning of the function body.
  291. // FIXME: do we need the first subcondition?
  292. if (!MI.getFlag(MachineInstr::FrameSetup) && MI.getDebugLoc()) {
  293. PrologEndLoc = MI.getDebugLoc();
  294. break;
  295. }
  296. EmptyPrologue = false;
  297. }
  298. }
  299. // Record beginning of function if we have a non-empty prologue.
  300. if (PrologEndLoc && !EmptyPrologue) {
  301. DebugLoc FnStartDL = PrologEndLoc.getFnDebugLoc();
  302. maybeRecordLocation(FnStartDL, MF);
  303. }
  304. }
  305. void WinCodeViewLineTables::endFunction(const MachineFunction *MF) {
  306. if (!Asm || !CurFn) // We haven't created any debug info for this function.
  307. return;
  308. const Function *GV = MF->getFunction();
  309. assert(FnDebugInfo.count(GV));
  310. assert(CurFn == &FnDebugInfo[GV]);
  311. if (CurFn->Instrs.empty()) {
  312. FnDebugInfo.erase(GV);
  313. VisitedFunctions.pop_back();
  314. } else {
  315. CurFn->End = Asm->getFunctionEnd();
  316. }
  317. CurFn = nullptr;
  318. }
  319. void WinCodeViewLineTables::beginInstruction(const MachineInstr *MI) {
  320. // Ignore DBG_VALUE locations and function prologue.
  321. if (!Asm || MI->isDebugValue() || MI->getFlag(MachineInstr::FrameSetup))
  322. return;
  323. DebugLoc DL = MI->getDebugLoc();
  324. if (DL == PrevInstLoc || !DL)
  325. return;
  326. maybeRecordLocation(DL, Asm->MF);
  327. }
  328. }