[LLVM-C] Expose functions to create debug locations via DIBuilder.
authorwhitequark <whitequark@whitequark.org>
Wed, 1 Nov 2017 22:18:52 +0000 (22:18 +0000)
committerwhitequark <whitequark@whitequark.org>
Wed, 1 Nov 2017 22:18:52 +0000 (22:18 +0000)
These include:
  * Several functions for creating an LLVMDIBuilder,
  * LLVMDIBuilderCreateCompileUnit,
  * LLVMDIBuilderCreateFile,
  * LLVMDIBuilderCreateDebugLocation.

Patch by Harlan Haskins.

Differential Revision: https://reviews.llvm.org/D32368

llvm-svn: 317135

llvm/include/llvm-c/DebugInfo.h [new file with mode: 0644]
llvm/lib/IR/DebugInfo.cpp
llvm/test/Bindings/llvm-c/debug_info.ll [new file with mode: 0644]
llvm/tools/llvm-c-test/CMakeLists.txt
llvm/tools/llvm-c-test/debuginfo.c [new file with mode: 0644]
llvm/tools/llvm-c-test/llvm-c-test.h
llvm/tools/llvm-c-test/main.c

diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h
new file mode 100644 (file)
index 0000000..c84765b
--- /dev/null
@@ -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
index ae044b3..b34383f 100644 (file)
 //
 //===----------------------------------------------------------------------===//
 
-#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<DIFile>(FileRef);
+
+  return wrap(unwrap(Builder)->createCompileUnit(
+                 map_from_llvmDWARFsourcelanguage(Lang), File,
+                 StringRef(Producer, ProducerLen), isOptimized,
+                 StringRef(Flags, FlagsLen), RuntimeVer,
+                 StringRef(SplitName, SplitNameLen),
+                 static_cast<DICompileUnit::DebugEmissionKind>(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/llvm/test/Bindings/llvm-c/debug_info.ll b/llvm/test/Bindings/llvm-c/debug_info.ll
new file mode 100644 (file)
index 0000000..7c62abf
--- /dev/null
@@ -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: ".")
index a2bde0d..bce0f4a 100644 (file)
@@ -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/llvm/tools/llvm-c-test/debuginfo.c b/llvm/tools/llvm-c-test/debuginfo.c
new file mode 100644 (file)
index 0000000..2da3887
--- /dev/null
@@ -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 <string.h>
+#include <stdio.h>
+
+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;
+}
index 2a70904..cf9a0f9 100644 (file)
@@ -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);
index 9bc0c96..5130783 100644 (file)
@@ -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();
   }