From 8b4e833a6e12d6bc11d3f5802ddcec657dc9205e Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 1 Nov 2017 22:18:52 +0000 Subject: [PATCH] [LLVM-C] Expose functions to create debug locations via DIBuilder. These include: * Several functions for creating an LLVMDIBuilder, * LLVMDIBuilderCreateCompileUnit, * LLVMDIBuilderCreateFile, * LLVMDIBuilderCreateDebugLocation. Patch by Harlan Haskins. Differential Revision: https://reviews.llvm.org/D32368 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@317135 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm-c/DebugInfo.h | 202 +++++++++++++++++++++++++++++ lib/IR/DebugInfo.cpp | 82 +++++++++++- test/Bindings/llvm-c/debug_info.ll | 8 ++ tools/llvm-c-test/CMakeLists.txt | 1 + tools/llvm-c-test/debuginfo.c | 38 ++++++ tools/llvm-c-test/llvm-c-test.h | 3 + tools/llvm-c-test/main.c | 5 + 7 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 include/llvm-c/DebugInfo.h create mode 100644 test/Bindings/llvm-c/debug_info.ll create mode 100644 tools/llvm-c-test/debuginfo.c diff --git a/include/llvm-c/DebugInfo.h b/include/llvm-c/DebugInfo.h new file mode 100644 index 00000000000..c84765b0dd7 --- /dev/null +++ b/include/llvm-c/DebugInfo.h @@ -0,0 +1,202 @@ +//===------------ DebugInfo.h - LLVM C API Debug Info API -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This file declares the C API endpoints for generating DWARF Debug Info +/// +/// Note: This interface is experimental. It is *NOT* stable, and may be +/// changed without warning. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-c/Core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/// Debug info flags. +typedef enum { + LLVMDIFlagZero = 0, + LLVMDIFlagPrivate = 1, + LLVMDIFlagProtected = 2, + LLVMDIFlagPublic = 3, + LLVMDIFlagFwdDecl = 1 << 2, + LLVMDIFlagAppleBlock = 1 << 3, + LLVMDIFlagBlockByrefStruct = 1 << 4, + LLVMDIFlagVirtual = 1 << 5, + LLVMDIFlagArtificial = 1 << 6, + LLVMDIFlagExplicit = 1 << 7, + LLVMDIFlagPrototyped = 1 << 8, + LLVMDIFlagObjcClassComplete = 1 << 9, + LLVMDIFlagObjectPointer = 1 << 10, + LLVMDIFlagVector = 1 << 11, + LLVMDIFlagStaticMember = 1 << 12, + LLVMDIFlagLValueReference = 1 << 13, + LLVMDIFlagRValueReference = 1 << 14, + LLVMDIFlagReserved = 1 << 15, + LLVMDIFlagSingleInheritance = 1 << 16, + LLVMDIFlagMultipleInheritance = 2 << 16, + LLVMDIFlagVirtualInheritance = 3 << 16, + LLVMDIFlagIntroducedVirtual = 1 << 18, + LLVMDIFlagBitField = 1 << 19, + LLVMDIFlagNoReturn = 1 << 20, + LLVMDIFlagMainSubprogram = 1 << 21, + LLVMDIFlagIndirectVirtualBase = (1 << 2) | (1 << 5), + LLVMDIFlagAccessibility = LLVMDIFlagPrivate | LLVMDIFlagProtected | + LLVMDIFlagPublic, + LLVMDIFlagPtrToMemberRep = LLVMDIFlagSingleInheritance | + LLVMDIFlagMultipleInheritance | + LLVMDIFlagVirtualInheritance +} LLVMDIFlags; + +/// Source languages known by DWARF. +typedef enum { + LLVMDWARFSourceLanguageC89, + LLVMDWARFSourceLanguageC, + LLVMDWARFSourceLanguageAda83, + LLVMDWARFSourceLanguageC_plus_plus, + LLVMDWARFSourceLanguageCobol74, + LLVMDWARFSourceLanguageCobol85, + LLVMDWARFSourceLanguageFortran77, + LLVMDWARFSourceLanguageFortran90, + LLVMDWARFSourceLanguagePascal83, + LLVMDWARFSourceLanguageModula2, + // New in DWARF v3: + LLVMDWARFSourceLanguageJava, + LLVMDWARFSourceLanguageC99, + LLVMDWARFSourceLanguageAda95, + LLVMDWARFSourceLanguageFortran95, + LLVMDWARFSourceLanguagePLI, + LLVMDWARFSourceLanguageObjC, + LLVMDWARFSourceLanguageObjC_plus_plus, + LLVMDWARFSourceLanguageUPC, + LLVMDWARFSourceLanguageD, + // New in DWARF v4: + LLVMDWARFSourceLanguagePython, + // New in DWARF v5: + LLVMDWARFSourceLanguageOpenCL, + LLVMDWARFSourceLanguageGo, + LLVMDWARFSourceLanguageModula3, + LLVMDWARFSourceLanguageHaskell, + LLVMDWARFSourceLanguageC_plus_plus_03, + LLVMDWARFSourceLanguageC_plus_plus_11, + LLVMDWARFSourceLanguageOCaml, + LLVMDWARFSourceLanguageRust, + LLVMDWARFSourceLanguageC11, + LLVMDWARFSourceLanguageSwift, + LLVMDWARFSourceLanguageJulia, + LLVMDWARFSourceLanguageDylan, + LLVMDWARFSourceLanguageC_plus_plus_14, + LLVMDWARFSourceLanguageFortran03, + LLVMDWARFSourceLanguageFortran08, + LLVMDWARFSourceLanguageRenderScript, + LLVMDWARFSourceLanguageBLISS, + // Vendor extensions: + LLVMDWARFSourceLanguageMips_Assembler, + LLVMDWARFSourceLanguageGOOGLE_RenderScript, + LLVMDWARFSourceLanguageBORLAND_Delphi +} LLVMDWARFSourceLanguage; + +/// The amount of debug information to emit. +typedef enum { + LLVMDWARFEmissionNone = 0, + LLVMDWARFEmissionFull, + LLVMDWARFEmissionLineTablesOnly +} LLVMDWARFEmissionKind; + +/// The current debug metadata version number. +unsigned LLVMDebugMetadataVersion(void); + +/// The version of debug metadata that's present in the provided \c Module. +unsigned LLVMGetModuleDebugMetadataVersion(LLVMModuleRef Module); + +/// Strip debug info in the module if it exists. +/// +/// To do this, we remove all calls to the debugger intrinsics and any named +/// metadata for debugging. We also remove debug locations for instructions. +/// Return true if module is modified. +LLVMBool LLVMStripModuleDebugInfo(LLVMModuleRef Module); + +/// Construct a builder for a module, and do not allow for unresolved nodes +/// attached to the module. +LLVMDIBuilderRef LLVMCreateDIBuilderDisallowUnresolved(LLVMModuleRef M); + +/// Construct a builder for a module and collect unresolved nodes attached +/// to the module in order to resolve cycles during a call to +/// \c LLVMDIBuilderFinalize. +LLVMDIBuilderRef LLVMCreateDIBuilder(LLVMModuleRef M); + +/// Deallocates the DIBuilder and everything it owns. +/// @note You must call \c LLVMDIBuilderFinalize before this +void LLVMDisposeDIBuilder(LLVMDIBuilderRef Builder); + +/// Construct any deferred debug info descriptors. +void LLVMDIBuilderFinalize(LLVMDIBuilderRef Builder); + +/// A CompileUnit provides an anchor for all debugging +/// information generated during this instance of compilation. +/// \param Lang Source programming language, eg. +/// \c LLVMDWARFSourceLanguageC99 +/// \param File File info. +/// \param Producer Identify the producer of debugging information +/// and code. Usually this is a compiler +/// version string. +/// \param ProducerLen The length of the C string passed to \c Producer. +/// \param isOptimized A boolean flag which indicates whether optimization +/// is enabled or not. +/// \param Flags This string lists command line options. This +/// string is directly embedded in debug info +/// output which may be used by a tool +/// analyzing generated debugging information. +/// \param FlagsLen The length of the C string passed to \c Flags. +/// \param RuntimeVer This indicates runtime version for languages like +/// Objective-C. +/// \param SplitName The name of the file that we'll split debug info +/// out into. +/// \param SplitNameLen The length of the C string passed to \c SplitName. +/// \param Kind The kind of debug information to generate. +/// \param DWOId The DWOId if this is a split skeleton compile unit. +/// \param SplitDebugInlining Whether to emit inline debug info. +/// \param DebugInfoForProfiling Whether to emit extra debug info for +/// profile collection. +LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( + LLVMDIBuilderRef Builder, LLVMDWARFSourceLanguage Lang, + LLVMMetadataRef FileRef, const char *Producer, size_t ProducerLen, + LLVMBool isOptimized, const char *Flags, size_t FlagsLen, + unsigned RuntimeVer, const char *SplitName, size_t SplitNameLen, + LLVMDWARFEmissionKind Kind, unsigned DWOId, LLVMBool SplitDebugInlining, + LLVMBool DebugInfoForProfiling); + +/// Create a file descriptor to hold debugging information for a file. +/// \param Builder The DIBuilder. +/// \param Filename File name. +/// \param FilenameLen The length of the C string passed to \c Filename. +/// \param Directory Directory. +/// \param DirectoryLen The length of the C string passed to \c Directory. +LLVMMetadataRef +LLVMDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename, + size_t FilenameLen, const char *Directory, + size_t DirectoryLen); + +/// Creates a new DebugLocation that describes a source location. +/// \param Line The line in the source file. +/// \param Column The column in the source file. +/// \param Scope The scope in which the location resides. +/// \param InlinedAt The scope where this location was inlined, if at all. +/// (optional). +/// \note If the item to which this location is attached cannot be +/// attributed to a source line, pass 0 for the line and column. +LLVMMetadataRef +LLVMDIBuilderCreateDebugLocation(LLVMContextRef Ctx, unsigned Line, + unsigned Column, LLVMMetadataRef Scope, + LLVMMetadataRef InlinedAt); + +#ifdef __cplusplus +} // end extern "C" +#endif diff --git a/lib/IR/DebugInfo.cpp b/lib/IR/DebugInfo.cpp index ae044b3d287..b34383f5ada 100644 --- a/lib/IR/DebugInfo.cpp +++ b/lib/IR/DebugInfo.cpp @@ -12,10 +12,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/DebugInfo.h" +#include "llvm-c/DebugInfo.h" +#include "LLVMContextImpl.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -23,6 +25,8 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/GVMaterializer.h" #include "llvm/IR/Instruction.h" @@ -692,3 +696,79 @@ void Instruction::applyMergedLocation(const DILocation *LocA, setDebugLoc(DILocation::get( Result->getContext(), 0, 0, Result->getScope(), Result->getInlinedAt())); } + +//===----------------------------------------------------------------------===// +// LLVM C API implementations. +//===----------------------------------------------------------------------===// + +static unsigned map_from_llvmDWARFsourcelanguage(LLVMDWARFSourceLanguage lang) { + switch (lang) { +#define HANDLE_DW_LANG(ID, NAME, VERSION, VENDOR) \ +case LLVMDWARFSourceLanguage##NAME: return ID; +#include "llvm/BinaryFormat/Dwarf.def" +#undef HANDLE_DW_LANG + } + llvm_unreachable("Unhandled Tag"); +} + +unsigned LLVMDebugMetadataVersion() { + return DEBUG_METADATA_VERSION; +} + +LLVMDIBuilderRef LLVMCreateDIBuilderDisallowUnresolved(LLVMModuleRef M) { + return wrap(new DIBuilder(*unwrap(M), false)); +} + +LLVMDIBuilderRef LLVMCreateDIBuilder(LLVMModuleRef M) { + return wrap(new DIBuilder(*unwrap(M))); +} + +unsigned LLVMGetModuleDebugMetadataVersion(LLVMModuleRef M) { + return getDebugMetadataVersionFromModule(*unwrap(M)); +} + +LLVMBool LLVMStripModuleDebugInfo(LLVMModuleRef M) { + return StripDebugInfo(*unwrap(M)); +} + +void LLVMDisposeDIBuilder(LLVMDIBuilderRef Builder) { + delete unwrap(Builder); +} + +void LLVMDIBuilderFinalize(LLVMDIBuilderRef Builder) { + unwrap(Builder)->finalize(); +} + +LLVMMetadataRef LLVMDIBuilderCreateCompileUnit( + LLVMDIBuilderRef Builder, LLVMDWARFSourceLanguage Lang, + LLVMMetadataRef FileRef, const char *Producer, size_t ProducerLen, + LLVMBool isOptimized, const char *Flags, size_t FlagsLen, + unsigned RuntimeVer, const char *SplitName, size_t SplitNameLen, + LLVMDWARFEmissionKind Kind, unsigned DWOId, LLVMBool SplitDebugInlining, + LLVMBool DebugInfoForProfiling) { + auto File = unwrap(FileRef); + + return wrap(unwrap(Builder)->createCompileUnit( + map_from_llvmDWARFsourcelanguage(Lang), File, + StringRef(Producer, ProducerLen), isOptimized, + StringRef(Flags, FlagsLen), RuntimeVer, + StringRef(SplitName, SplitNameLen), + static_cast(Kind), DWOId, + SplitDebugInlining, DebugInfoForProfiling)); +} + +LLVMMetadataRef +LLVMDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename, + size_t FilenameLen, const char *Directory, + size_t DirectoryLen) { + return wrap(unwrap(Builder)->createFile(StringRef(Filename, FilenameLen), + StringRef(Directory, DirectoryLen))); +} + +LLVMMetadataRef +LLVMDIBuilderCreateDebugLocation(LLVMContextRef Ctx, unsigned Line, + unsigned Column, LLVMMetadataRef Scope, + LLVMMetadataRef InlinedAt) { + return wrap(DILocation::get(*unwrap(Ctx), Line, Column, unwrap(Scope), + unwrap(InlinedAt))); +} diff --git a/test/Bindings/llvm-c/debug_info.ll b/test/Bindings/llvm-c/debug_info.ll new file mode 100644 index 00000000000..7c62abfae5c --- /dev/null +++ b/test/Bindings/llvm-c/debug_info.ll @@ -0,0 +1,8 @@ +; RUN: llvm-c-test --test-dibuilder | FileCheck %s + +; CHECK: ; ModuleID = 'debuginfo.c' +; CHECK-NEXT: source_filename = "debuginfo.c" + +; CHECK: !llvm.dbg.cu = !{!0} +; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "llvm-c-test", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false) +; CHECK-NEXT: !1 = !DIFile(filename: "debuginfo.c\00", directory: ".") diff --git a/tools/llvm-c-test/CMakeLists.txt b/tools/llvm-c-test/CMakeLists.txt index a2bde0d9714..bce0f4a5a42 100644 --- a/tools/llvm-c-test/CMakeLists.txt +++ b/tools/llvm-c-test/CMakeLists.txt @@ -38,6 +38,7 @@ endif () add_llvm_tool(llvm-c-test attributes.c calc.c + debuginfo.c diagnostic.c disassemble.c echo.cpp diff --git a/tools/llvm-c-test/debuginfo.c b/tools/llvm-c-test/debuginfo.c new file mode 100644 index 00000000000..2da3887a172 --- /dev/null +++ b/tools/llvm-c-test/debuginfo.c @@ -0,0 +1,38 @@ +/*===-- debuginfo.c - tool for testing libLLVM and llvm-c API -------------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Tests for the LLVM C DebugInfo API *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/DebugInfo.h" +#include +#include + +int llvm_test_dibuilder() { + LLVMModuleRef M = LLVMModuleCreateWithName("debuginfo.c"); + LLVMDIBuilderRef DIB = LLVMCreateDIBuilder(M); + + LLVMMetadataRef File = LLVMDIBuilderCreateFile(DIB, "debuginfo.c", 12, + ".", 1); + + LLVMDIBuilderCreateCompileUnit(DIB, + LLVMDWARFSourceLanguageC, File,"llvm-c-test", 11, 0, NULL, 0, 0, + NULL, 0, LLVMDWARFEmissionFull, 0, 0, 0); + + char *MStr = LLVMPrintModuleToString(M); + puts(MStr); + LLVMDisposeMessage(MStr); + + LLVMDisposeDIBuilder(DIB); + LLVMDisposeModule(M); + + return 0; +} diff --git a/tools/llvm-c-test/llvm-c-test.h b/tools/llvm-c-test/llvm-c-test.h index 2a7090484b0..cf9a0f99de6 100644 --- a/tools/llvm-c-test/llvm-c-test.h +++ b/tools/llvm-c-test/llvm-c-test.h @@ -35,6 +35,9 @@ int llvm_calc(void); // disassemble.c int llvm_disassemble(void); +// debuginfo.c +int llvm_test_dibuilder(void); + // metadata.c int llvm_add_named_metadata_operand(void); int llvm_set_metadata(void); diff --git a/tools/llvm-c-test/main.c b/tools/llvm-c-test/main.c index 9bc0c96c3d6..5130783d6a6 100644 --- a/tools/llvm-c-test/main.c +++ b/tools/llvm-c-test/main.c @@ -55,6 +55,9 @@ static void print_usage(void) { fprintf(stderr, " * --test-diagnostic-handler\n"); fprintf(stderr, " Read bitcode file form stdin with a diagnostic handler set\n\n"); + fprintf(stderr, " * --test-dibuilder\n"); + fprintf(stderr, + " Run tests for the DIBuilder C API - print generated module\n\n"); } int main(int argc, char **argv) { @@ -96,6 +99,8 @@ int main(int argc, char **argv) { return llvm_echo(); } else if (argc == 2 && !strcmp(argv[1], "--test-diagnostic-handler")) { return llvm_test_diagnostic_handler(); + } else if (argc == 2 && !strcmp(argv[1], "--test-dibuilder")) { + return llvm_test_dibuilder(); } else { print_usage(); } -- 2.40.0