[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

llvm-svn: 317135
This commit is contained in:
whitequark 2017-11-01 22:18:52 +00:00
parent 3837322a6b
commit 789164d426
7 changed files with 338 additions and 1 deletions

View File

@ -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

View File

@ -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/DenseMap.h"
#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/None.h" #include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
@ -23,6 +25,8 @@
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h" #include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/Function.h" #include "llvm/IR/Function.h"
#include "llvm/IR/GVMaterializer.h" #include "llvm/IR/GVMaterializer.h"
#include "llvm/IR/Instruction.h" #include "llvm/IR/Instruction.h"
@ -692,3 +696,79 @@ void Instruction::applyMergedLocation(const DILocation *LocA,
setDebugLoc(DILocation::get( setDebugLoc(DILocation::get(
Result->getContext(), 0, 0, Result->getScope(), Result->getInlinedAt())); 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)));
}

View File

@ -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: ".")

View File

@ -38,6 +38,7 @@ endif ()
add_llvm_tool(llvm-c-test add_llvm_tool(llvm-c-test
attributes.c attributes.c
calc.c calc.c
debuginfo.c
diagnostic.c diagnostic.c
disassemble.c disassemble.c
echo.cpp echo.cpp

View File

@ -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;
}

View File

@ -35,6 +35,9 @@ int llvm_calc(void);
// disassemble.c // disassemble.c
int llvm_disassemble(void); int llvm_disassemble(void);
// debuginfo.c
int llvm_test_dibuilder(void);
// metadata.c // metadata.c
int llvm_add_named_metadata_operand(void); int llvm_add_named_metadata_operand(void);
int llvm_set_metadata(void); int llvm_set_metadata(void);

View File

@ -55,6 +55,9 @@ static void print_usage(void) {
fprintf(stderr, " * --test-diagnostic-handler\n"); fprintf(stderr, " * --test-diagnostic-handler\n");
fprintf(stderr, fprintf(stderr,
" Read bitcode file form stdin with a diagnostic handler set\n\n"); " 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) { int main(int argc, char **argv) {
@ -96,6 +99,8 @@ int main(int argc, char **argv) {
return llvm_echo(); return llvm_echo();
} else if (argc == 2 && !strcmp(argv[1], "--test-diagnostic-handler")) { } else if (argc == 2 && !strcmp(argv[1], "--test-diagnostic-handler")) {
return llvm_test_diagnostic_handler(); return llvm_test_diagnostic_handler();
} else if (argc == 2 && !strcmp(argv[1], "--test-dibuilder")) {
return llvm_test_dibuilder();
} else { } else {
print_usage(); print_usage();
} }