Skip to content

Commit

Permalink
[LLVM-C] Expose functions to create debug locations via DIBuilder.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
whitequark committed Nov 1, 2017
1 parent 3837322 commit 789164d
Show file tree
Hide file tree
Showing 7 changed files with 338 additions and 1 deletion.
202 changes: 202 additions & 0 deletions llvm/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
82 changes: 81 additions & 1 deletion llvm/lib/IR/DebugInfo.cpp
Expand Up @@ -12,17 +12,21 @@
//
//===----------------------------------------------------------------------===//

#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"
#include "llvm/IR/BasicBlock.h"
#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"
Expand Down Expand Up @@ -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)));
}
8 changes: 8 additions & 0 deletions llvm/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: ".")
1 change: 1 addition & 0 deletions llvm/tools/llvm-c-test/CMakeLists.txt
Expand Up @@ -38,6 +38,7 @@ endif ()
add_llvm_tool(llvm-c-test
attributes.c
calc.c
debuginfo.c
diagnostic.c
disassemble.c
echo.cpp
Expand Down
38 changes: 38 additions & 0 deletions llvm/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 <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;
}
3 changes: 3 additions & 0 deletions llvm/tools/llvm-c-test/llvm-c-test.h
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions llvm/tools/llvm-c-test/main.c
Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
}
Expand Down

0 comments on commit 789164d

Please sign in to comment.