# This patch allows ISPC code to be debugged in Visual Studio 2012 and above # Requires LLVM 3.5 Index: include/llvm/Support/COFF.h =================================================================== --- include/llvm/Support/COFF.h (revision 215535) +++ include/llvm/Support/COFF.h (working copy) @@ -642,9 +642,14 @@ enum CodeViewLineTableIdentifiers { DEBUG_SECTION_MAGIC = 0x4, + DEBUG_SYMBOL_SUBSECTION = 0xF1, DEBUG_LINE_TABLE_SUBSECTION = 0xF2, DEBUG_STRING_TABLE_SUBSECTION = 0xF3, - DEBUG_INDEX_SUBSECTION = 0xF4 + DEBUG_INDEX_SUBSECTION = 0xF4, + + // Symbol subsections are split into subsubsections. + DEBUG_SYMBOL_PROC_START_SUBSUBSECTION = 0x1147, + DEBUG_SYMBOL_PROC_END_SUBSUBSECTION = 0x114F }; inline bool isReservedSectionNumber(int N) { Index: lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp =================================================================== --- lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp (revision 215535) +++ lib/CodeGen/AsmPrinter/WinCodeViewLineTables.cpp (working copy) @@ -117,14 +117,15 @@ } static void EmitLabelDiff(MCStreamer &Streamer, - const MCSymbol *From, const MCSymbol *To) { + const MCSymbol *From, const MCSymbol *To, + unsigned int Size = 4) { MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; MCContext &Context = Streamer.getContext(); const MCExpr *FromRef = MCSymbolRefExpr::Create(From, Variant, Context), *ToRef = MCSymbolRefExpr::Create(To, Variant, Context); const MCExpr *AddrDelta = MCBinaryExpr::Create(MCBinaryExpr::Sub, ToRef, FromRef, Context); - Streamer.EmitValue(AddrDelta, 4); + Streamer.EmitValue(AddrDelta, Size); } void WinCodeViewLineTables::emitDebugInfoForFunction(const Function *GV) { @@ -132,12 +133,50 @@ // which holds the PC to file:line table. const MCSymbol *Fn = Asm->getSymbol(GV); assert(Fn); + const StringRef FuncName = Fn->getName(); const FunctionInfo &FI = FnDebugInfo[GV]; if (FI.Instrs.empty()) return; assert(FI.End && "Don't know where the function ends?"); + // Emit a symbol subsection, required by VS2012+ to find function boundaries. + MCSymbol *SymbolsBegin = Asm->MMI->getContext().CreateTempSymbol(), + *SymbolsEnd = Asm->MMI->getContext().CreateTempSymbol(); + Asm->OutStreamer.AddComment("Symbol subsection for " + Twine(FuncName)); + Asm->EmitInt32(COFF::DEBUG_SYMBOL_SUBSECTION); + EmitLabelDiff(Asm->OutStreamer, SymbolsBegin, SymbolsEnd); + Asm->OutStreamer.EmitLabel(SymbolsBegin); + { + MCSymbol *ProcSegmentBegin = Asm->MMI->getContext().CreateTempSymbol(), + *ProcSegmentEnd = Asm->MMI->getContext().CreateTempSymbol(); + EmitLabelDiff(Asm->OutStreamer, ProcSegmentBegin, ProcSegmentEnd, 2); + Asm->OutStreamer.EmitLabel(ProcSegmentBegin); + + Asm->EmitInt16(COFF::DEBUG_SYMBOL_PROC_START_SUBSUBSECTION); + // Some bytes of this segment don't seem to be required for basic debugging, + // so just fill them with zeroes. + Asm->OutStreamer.EmitFill(12, 0); + // This is the important bit that tells the debugger where the function + // code is located: + EmitLabelDiff(Asm->OutStreamer, Fn, FI.End); + Asm->OutStreamer.EmitFill(12, 0); + Asm->OutStreamer.EmitCOFFSecRel32(Fn); + Asm->OutStreamer.EmitCOFFSectionIndex(Fn); + Asm->EmitInt8(0); + // Emit the function name as a null-terminated string. + Asm->OutStreamer.EmitBytes(FuncName); + Asm->EmitInt8(0); + Asm->OutStreamer.EmitLabel(ProcSegmentEnd); + + // We're done with this function. + Asm->EmitInt16(0x0002); + Asm->EmitInt16(COFF::DEBUG_SYMBOL_PROC_END_SUBSUBSECTION); + } + Asm->OutStreamer.EmitLabel(SymbolsEnd); + // Every subsection must be aligned to a 4-byte boundary. + Asm->OutStreamer.EmitFill((-FuncName.size()) % 4, 0); + // PCs/Instructions are grouped into segments sharing the same filename. // Pre-calculate the lengths (in instructions) of these segments and store // them in a map for convenience. Each index in the map is the sequential @@ -154,18 +193,18 @@ } FilenameSegmentLengths[LastSegmentEnd] = FI.Instrs.size() - LastSegmentEnd; - // Emit the control code of the subsection followed by the payload size. - Asm->OutStreamer.AddComment( - "Linetable subsection for " + Twine(Fn->getName())); + // Emit a linetable subsection, requred to do PC-to-file:line lookup. + Asm->OutStreamer.AddComment("Linetable subsection for " + Twine(FuncName)); Asm->EmitInt32(COFF::DEBUG_LINE_TABLE_SUBSECTION); - MCSymbol *SubsectionBegin = Asm->MMI->getContext().CreateTempSymbol(), - *SubsectionEnd = Asm->MMI->getContext().CreateTempSymbol(); - EmitLabelDiff(Asm->OutStreamer, SubsectionBegin, SubsectionEnd); - Asm->OutStreamer.EmitLabel(SubsectionBegin); + MCSymbol *LineTableBegin = Asm->MMI->getContext().CreateTempSymbol(), + *LineTableEnd = Asm->MMI->getContext().CreateTempSymbol(); + EmitLabelDiff(Asm->OutStreamer, LineTableBegin, LineTableEnd); + Asm->OutStreamer.EmitLabel(LineTableBegin); // Identify the function this subsection is for. Asm->OutStreamer.EmitCOFFSecRel32(Fn); Asm->OutStreamer.EmitCOFFSectionIndex(Fn); + Asm->EmitInt16(0); // Length of the function's code, in bytes. EmitLabelDiff(Asm->OutStreamer, Fn, FI.End); @@ -209,7 +248,7 @@ if (FileSegmentEnd) Asm->OutStreamer.EmitLabel(FileSegmentEnd); - Asm->OutStreamer.EmitLabel(SubsectionEnd); + Asm->OutStreamer.EmitLabel(LineTableEnd); } void WinCodeViewLineTables::endModule() { @@ -254,8 +293,7 @@ Asm->OutStreamer.EmitBytes(FileNameRegistry.Filenames[I]); Asm->EmitInt8(0); } - - // No more subsections. Fill with zeros to align the end of the section by 4. + // Every subsection must be aligned to a 4-byte boundary. Asm->OutStreamer.EmitFill((-FileNameRegistry.LastOffset) % 4, 0); clear(); Index: lib/MC/WinCOFFStreamer.cpp =================================================================== --- lib/MC/WinCOFFStreamer.cpp (revision 215535) +++ lib/MC/WinCOFFStreamer.cpp (working copy) @@ -163,7 +163,7 @@ const MCSymbolRefExpr *SRE = MCSymbolRefExpr::Create(Symbol, getContext()); MCFixup Fixup = MCFixup::Create(DF->getContents().size(), SRE, FK_SecRel_2); DF->getFixups().push_back(Fixup); - DF->getContents().resize(DF->getContents().size() + 4, 0); + DF->getContents().resize(DF->getContents().size() + 2, 0); } void MCWinCOFFStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) {