From 89ebbaeb6c13461c38426e0ebbbb2b9ae95eabff Mon Sep 17 00:00:00 2001 From: Vasily Levchenko Date: Mon, 13 Mar 2017 18:55:49 +0300 Subject: [PATCH] DEBUGINFO: initial C bindings to debug info llvm - support DICompileUnit - support DIFIle - support DISubroutine - support DIBasicType - support DILocation - added gradle build - debug info bindings are involved in kotlin build - added binding to DIGetSubprogramLinkName - added binding to LLVMBuilderGetCurrentFunction - added reset location - simple demo added (buildable with gradle) produces folowing output: Following pseudo code in sources. 0:123456789012345678901 1: fun main():Int { 2: {foo()}() 3: return 0 4: } 5 fun foo() {} 0:b-backend-dwarf:minamoto@unit-703(0)# ./demo ; ModuleID = 'test' source_filename = "test" define i32 @foo(i32) !dbg !3 { entry: ret i32 %0, !dbg !7 } !llvm.dbg.cu = !{!0} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "konanc", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) !1 = !DIFile(filename: "1.kt", directory: "src") !2 = !{} !3 = distinct !DISubprogram(name: "foo", linkageName: "foo:link", scope: null, file: !1, line: 66, type: !4, isLocal: false, isDefinition: true, isOptimized: false, unit: !0, variables: !2) !4 = !DISubroutineType(types: !5) !5 = !{!6} !6 = !DIBasicType(name: "int", size: 32, align: 4) !7 = !DILocation(line: 42, column: 15, scope: !3) - demo sharing debug information between several bitcode artifacts 0:b-backend-dwarf:minamoto@unit-703(0)# llvmDebugInfoC/build/exe/demogenerated/demogenerated ; ModuleID = 'test' source_filename = "test" define void @foo() !dbg !3 { entry: ret void, !dbg !5 } define void @"main$caller$foo"() !dbg !6 { entry: call void @foo(), !dbg !7 ret void } define void @main() !dbg !8 { entry: call void @"main$caller$foo"(), !dbg !9 ret void, !dbg !10 } !llvm.dbg.cu = !{!0} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "konanc", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) !1 = !DIFile(filename: "", directory: "") !2 = !{} !3 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 5, type: !4, isLocal: false, isDefinition: true, isOptimized: false, unit: !0, variables: !2) !4 = !DISubroutineType(types: !2) !5 = !DILocation(line: 5, column: 14, scope: !3) !6 = distinct !DISubprogram(name: "main$caller$foo", linkageName: "main$caller$foo", scope: null, file: !1, line: 2, type: !4, isLocal: false, isDefinition: true, isOptimized: false, unit: !0, variables: !2) !7 = !DILocation(line: 5, column: 2, scope: !6) !8 = distinct !DISubprogram(name: "main", linkageName: "main", scope: null, file: !1, line: 1, type: !4, isLocal: false, isDefinition: true, isOptimized: false, unit: !0, variables: !2) !9 = !DILocation(line: 2, column: 12, scope: !8) !10 = !DILocation(line: 3, column: 4, scope: !8) - local variables support - demo for local variable suppor (TBD some out put here). ; ModuleID = 'test' source_filename = "test" define i32 @main() !dbg !3 { entry: %0 = alloca i32 call void @llvm.dbg.declare(metadata i32* %0, metadata !5, metadata !7), !dbg !8 store i32 42, i32* %0, !dbg !8 %1 = load i32, i32* %0, !dbg !8 ret i32 %1, !dbg !8 } ; Function Attrs: nounwind readnone declare void @llvm.dbg.declare(metadata, metadata, metadata) #0 attributes #0 = { nounwind readnone } !llvm.dbg.cu = !{!0} !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "konanc", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) !1 = !DIFile(filename: "", directory: "") !2 = !{} !3 = distinct !DISubprogram(name: "main", linkageName: "main", scope: null, file: !1, line: 1, type: !4, isLocal: false, isDefinition: true, isOptimized: false, unit: !0, variables: !2) !4 = !DISubroutineType(types: !2) !5 = !DILocalVariable(name: "a", scope: !3, file: !1, line: 2, type: !6) !6 = !DIBasicType(name: "int", size: 32, align: 4) !7 = !DIExpression() !8 = !DILocation(line: 2, column: 1, scope: !3) --- backend.native/build.gradle | 13 +- build.gradle | 10 + llvmDebugInfoC/build.gradle | 85 +++++++++ llvmDebugInfoC/debugInfo.def | 7 + llvmDebugInfoC/src/demo-generated/c/demo.c | 114 ++++++++++++ .../src/demo-local-variable/c/demo.c | 133 +++++++++++++ llvmDebugInfoC/src/demo-simple/c/demo.c | 118 ++++++++++++ llvmDebugInfoC/src/main/cpp/DebugInfoC.cpp | 176 ++++++++++++++++++ llvmDebugInfoC/src/main/include/DebugInfoC.h | 74 ++++++++ settings.gradle | 1 + 10 files changed, 730 insertions(+), 1 deletion(-) create mode 100644 llvmDebugInfoC/build.gradle create mode 100644 llvmDebugInfoC/debugInfo.def create mode 100644 llvmDebugInfoC/src/demo-generated/c/demo.c create mode 100644 llvmDebugInfoC/src/demo-local-variable/c/demo.c create mode 100644 llvmDebugInfoC/src/demo-simple/c/demo.c create mode 100644 llvmDebugInfoC/src/main/cpp/DebugInfoC.cpp create mode 100644 llvmDebugInfoC/src/main/include/DebugInfoC.h diff --git a/backend.native/build.gradle b/backend.native/build.gradle index a55f1f6496d..d7a3ecba40a 100644 --- a/backend.native/build.gradle +++ b/backend.native/build.gradle @@ -153,6 +153,15 @@ kotlinNativeInterop { linkerOpts llvmLinkerOpts() } + debugInfo { + dependsOn ":llvmDebugInfoC:debugInfoStaticLibrary" + defFile '../llvmDebugInfoC/debugInfo.def' + compilerOpts "-fPIC", "-I$llvmDir/include", "-I${project(':llvmDebugInfoC').projectDir}/src/main/include" + if (isLinux()) { + linker 'clang++' + } + } + hash { // TODO: copy-pasted from ':common:compileHash' compilerOpts '-fPIC' linkerOpts '-fPIC' @@ -184,6 +193,7 @@ dependencies { compilerCompile kotlinCompilerModule compilerCompile kotlinNativeInterop['llvm'].configuration compilerCompile kotlinNativeInterop['hash'].configuration + compilerCompile kotlinNativeInterop['debugInfo'].configuration cli_bcCompile "org.jetbrains.kotlin:kotlin-runtime:$kotlin_version" cli_bcCompile sourceSets.compiler.output @@ -264,7 +274,8 @@ task jars(type: Jar) { from 'build/classes/cli_bc', 'build/classes/compiler', 'build/classes/hashInteropStubs', - 'build/classes/llvmInteropStubs' + 'build/classes/llvmInteropStubs', + 'build/classes/debugInfoInteropStubs' dependsOn 'build', ':runtime:hostRuntime', 'external_jars' } diff --git a/build.gradle b/build.gradle index 57a145b9d7c..8756d0e92b9 100644 --- a/build.gradle +++ b/build.gradle @@ -202,6 +202,11 @@ task dist_compiler(type: Copy) { into('konan/nativelib') } + from(project(':llvmDebugInfoC').file('build/libs/debugInfo/shared')) { + into('konan/nativelib') + } + + from(file('cmd')) { fileMode(0755) into('bin') @@ -234,6 +239,11 @@ task dist_compiler(type: Copy) { args '-add_rpath', '@loader_path/', 'dist/konan/nativelib/libclangstubs.dylib' } + exec { + commandLine "install_name_tool" + args '-add_rpath', '@loader_path/', + 'dist/konan/nativelib/libdebugInfostubs.dylib' + } } } } diff --git a/llvmDebugInfoC/build.gradle b/llvmDebugInfoC/build.gradle new file mode 100644 index 00000000000..b49e639d98d --- /dev/null +++ b/llvmDebugInfoC/build.gradle @@ -0,0 +1,85 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: "cpp" +apply plugin: "c" + +model { + components { + debugInfo(NativeLibrarySpec) { + sources.cpp.source.srcDirs "src/main/cpp" + + binaries.all { + cppCompiler.args "--std=c++11", "-g", "-fPIC", "-I${llvmDir}/include", "-I${projectDir}/src/main/include" + linker.args "-L${llvmDir}/lib", "-lLLVMCore", "-lLLVMSupport" + } + } + + demosimple(NativeExecutableSpec) { + //dependsOn project("debugInfoStaticLibrary") + sources.c.source.srcDirs "src/demo-simple/c" + binaries.all { + cCompiler.args "-g", "-I${llvmDir}/include", + "-I${projectDir}/src/main/include" + if (targetPlatform.operatingSystem.linux) { + linker.args "-L${buildDir}/libs/debugInfo/static", "-ldebugInfo", + "-L${llvmDir}/lib", "-Wl,-(", "-lLLVMSupport", "-lLLVMCore", "-Wl,-)", + "-L/usr/lib/x86_64-linux-gnu", "-L/lib/x86_64-linux-gnu", "-lncurses", + "-ldl", "-lpthread" + } else { + linker.args "-L${llvmDir}/lib", "-lLLVMCore", "-lLLVMSupport", + "-lncurses", "-L${buildDir}/libs/debugInfo/static", "-ldebugInfo" + } + } + } + + demogenerated(NativeExecutableSpec) { + //dependsOn project("debugInfoStaticLibrary") + sources.c.source.srcDirs "src/demo-generated/c" + binaries.all { + cCompiler.args "-g", "-I${llvmDir}/include", + "-I${projectDir}/src/main/include" + if (targetPlatform.operatingSystem.linux) { + linker.args "-L${buildDir}/libs/debugInfo/static", "-ldebugInfo", + "-L${llvmDir}/lib", "-Wl,-(", "-lLLVMSupport", "-lLLVMAnalysis", "-lLLVMProfileData", "-lLLVMCore", "-Wl,-)", + "-L/usr/lib/x86_64-linux-gnu", "-L/lib/x86_64-linux-gnu", "-lncurses", "-lz", + "-ldl", "-lpthread" + } else { + linker.args "-L${llvmDir}/lib", "-lLLVMCore", "-lLLVMSupport", + "-lncurses", "-L${buildDir}/libs/debugInfo/static", "-ldebugInfo" + } + } + } + + demolocalvariable(NativeExecutableSpec) { + //dependsOn project("debugInfoStaticLibrary") + sources.c.source.srcDirs "src/demo-local-variable/c" + binaries.all { + cCompiler.args "-g", "-I${llvmDir}/include", + "-I${projectDir}/src/main/include" + if (targetPlatform.operatingSystem.linux) { + linker.args "-L${buildDir}/libs/debugInfo/static", "-ldebugInfo", + "-L${llvmDir}/lib", "-Wl,-(", "-lLLVMSupport", "-lLLVMAnalysis", "-lLLVMProfileData", "-lLLVMCore", "-Wl,-)", + "-L/usr/lib/x86_64-linux-gnu", "-L/lib/x86_64-linux-gnu", "-lncurses", "-lz", + "-ldl", "-lpthread" + } else { + linker.args "-L${llvmDir}/lib", "-lLLVMCore", "-lLLVMSupport", "-lLLVMAnalysis", "-lLLVMProfileData", + "-lncurses", "-L${buildDir}/libs/debugInfo/static", "-ldebugInfo", "-lz" + } + } + } + } +} diff --git a/llvmDebugInfoC/debugInfo.def b/llvmDebugInfoC/debugInfo.def new file mode 100644 index 00000000000..ac579c04cdf --- /dev/null +++ b/llvmDebugInfoC/debugInfo.def @@ -0,0 +1,7 @@ +headers = DebugInfoC.h + +compilerOpts=-fPIC +linkerOpts.osx = -Wl,-all_load -L../llvmDebugInfoC/build/libs/debugInfo/static -ldebugInfo +linkerOpts.linux = --Wl,--whole-archive -L../llvmDebugInfoC/build/libs/debugInfo/static -ldebugInfo --Wl,--no-whole-archive -lLLVMCore -lLLVMSupport +compilerOpts.osx = -IllvmDebugInfoC/include -Idependencies/all/clang+llvm-3.9.0-darwin-macos/include +compilerOpts.linux = -IllvmDebugInfoC/include -Idependencies/all/clang+llvm-3.9.0-linux-x86-64/include \ No newline at end of file diff --git a/llvmDebugInfoC/src/demo-generated/c/demo.c b/llvmDebugInfoC/src/demo-generated/c/demo.c new file mode 100644 index 00000000000..06ba3b8f621 --- /dev/null +++ b/llvmDebugInfoC/src/demo-generated/c/demo.c @@ -0,0 +1,114 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +/** + * this demo produces bitcode for case when several functions generated from one source code. + * e.g. for following source: + * 0:123456789012345678901 + * 1: fun main():Int { + * 2: {foo()}() + * 3: return 0 + * 4: } + * 5 fun foo() {} + * + * we produce following IR (line and column numbers are in parencies) + * fun main$caller$foo(2:4) + * call foo(5:2) + * fun main(1:2) + * call main$caller$foo(2:12) + * return0(3:4) + * fun foo(5:2) + * return(5:14) + */ + +LLVMModuleRef module; +DIBuilderRef di_builder; +LLVMBuilderRef llvm_builder; +DICompileUnitRef di_compile_unit; +DIFileRef file; +DISubroutineTypeRef subroutine_type; + +static LLVMValueRef +create_function(const char* name) { + LLVMTypeRef function_type = LLVMFunctionType(LLVMVoidType(), NULL, 0, 0); + return LLVMAddFunction(module, name, function_type); +} + +static DISubprogramRef +create_function_with_entry(const char *name, int line) { + LLVMValueRef function = create_function(name); + LLVMBasicBlockRef bb = LLVMAppendBasicBlock(function, "entry"); + DISubprogramRef di_function = DICreateFunction(di_builder, di_compile_unit, name, name, file, line, + subroutine_type, 0, 1, 0); + LLVMPositionBuilderAtEnd(llvm_builder, bb); + DIFunctionAddSubprogram(function, di_function); + return di_function; +} + +#define FOO_FUNCTION "foo" +#define MAIN_FUNCTION "main" +#define MAIN_CALLER_FOO_FUNCTION "main$caller$foo" + + +static void +create_foo() { + DISubprogramRef di = create_function_with_entry(FOO_FUNCTION, 5); + LLVMBuilderSetDebugLocation(llvm_builder, 5, 14, di); + LLVMBuildRetVoid(llvm_builder); +} + +static void +create_main_caller_foo() { + DISubprogramRef di = create_function_with_entry(MAIN_CALLER_FOO_FUNCTION, 2); + LLVMValueRef fn = LLVMGetNamedFunction(module, FOO_FUNCTION); + LLVMBuilderSetDebugLocation(llvm_builder, 5, 2, di); + LLVMBuildCall(llvm_builder, fn, NULL, 0, ""); + LLVMBuilderResetDebugLocation(llvm_builder); + LLVMBuildRetVoid(llvm_builder); +} + +static void +create_main() { + DISubprogramRef di = create_function_with_entry(MAIN_FUNCTION, 1); + LLVMValueRef fn = LLVMGetNamedFunction(module, MAIN_CALLER_FOO_FUNCTION); + LLVMBuilderSetDebugLocation(llvm_builder, 2, 12, di); + LLVMBuildCall(llvm_builder, fn, NULL, 0, ""); + LLVMBuilderSetDebugLocation(llvm_builder, 3, 4, di); + LLVMBuildRetVoid(llvm_builder); +} + + +int +main() { + module = LLVMModuleCreateWithName("test"); + di_builder = DICreateBuilder(module); + di_compile_unit = DICreateCompilationUnit(di_builder, 4, + "", "", + "konanc", 0, "", 0); + llvm_builder = LLVMCreateBuilderInContext(LLVMGetModuleContext(module)); + file = DICreateFile(di_builder, "", ""); + subroutine_type = DICreateSubroutineType(di_builder, NULL, 0); + create_foo(); + create_main_caller_foo(); + create_main(); + DIFinalize(di_builder); + + LLVMVerifyModule(module, LLVMPrintMessageAction, NULL); + LLVMDumpModule(module); +} diff --git a/llvmDebugInfoC/src/demo-local-variable/c/demo.c b/llvmDebugInfoC/src/demo-local-variable/c/demo.c new file mode 100644 index 00000000000..65763f7a2da --- /dev/null +++ b/llvmDebugInfoC/src/demo-local-variable/c/demo.c @@ -0,0 +1,133 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +/** + * 0:b-backend-dwarf:minamoto@unit-703(0)# clang -xc -S -g -emit-llvm -o - - + * "TERMCAP", line 20, col 1, terminal 'SC': Missing separator + * 12345678901234567890 + * 1:int main() { + * 2: int a = 42; + * 3: return a; + * 4:} + * ; ModuleID = '-' + * source_filename = "-" + * target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + * target triple = "x86_64-apple-macosx10.12.0" + * + * ; Function Attrs: nounwind ssp uwtable + * define i32 @main() #0 !dbg !7 { + * %1 = alloca i32, align 4 + * %2 = alloca i32, align 4 + * store i32 0, i32* %1, align 4 + * call void @llvm.dbg.declare(metadata i32* %2, metadata !12, metadata !13), !dbg !14 + * store i32 42, i32* %2, align 4, !dbg !14 + * %3 = load i32, i32* %2, align 4, !dbg !15 + * ret i32 %3, !dbg !16 + * } + * + * ; Function Attrs: nounwind readnone + * declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + * + * attributes #0 = { nounwind ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + * attributes #1 = { nounwind readnone } + * + * !llvm.dbg.cu = !{!0} + * !llvm.module.flags = !{!3, !4, !5} + * !llvm.ident = !{!6} + * + * !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Apple LLVM version 8.1.0 (clang-802.0.36)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + * !1 = !DIFile(filename: "-", directory: "/Users/minamoto/ws/.git-trees/backend-dwarf") + * !2 = !{} + * !3 = !{i32 2, !"Dwarf Version", i32 4} + * !4 = !{i32 2, !"Debug Info Version", i32 700000003} + * !5 = !{i32 1, !"PIC Level", i32 2} + * !6 = !{!"Apple LLVM version 8.1.0 (clang-802.0.36)"} + * !7 = distinct !DISubprogram(name: "main", scope: !8, file: !8, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, variables: !2) + * !8 = !DIFile(filename: "", directory: "/Users/minamoto/ws/.git-trees/backend-dwarf") + * !9 = !DISubroutineType(types: !10) + * !10 = !{!11} + * !11 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) + * !12 = !DILocalVariable(name: "a", scope: !7, file: !8, line: 2, type: !11) + * !13 = !DIExpression() + * !14 = !DILocation(line: 2, column: 7, scope: !7) + * !15 = !DILocation(line: 3, column: 10, scope: !7) + * !16 = !DILocation(line: 3, column: 3, scope: !7) + */ + +static LLVMModuleRef module; +static DIBuilderRef di_builder; +static LLVMBuilderRef llvm_builder; +static DICompileUnitRef di_compile_unit; +static DIFileRef file; +static DISubroutineTypeRef subroutine_type; +static LLVMTypeRef int_type; +static DITypeOpaqueRef di_int_type; + +static LLVMValueRef +create_function(const char* name) { + LLVMTypeRef function_type = LLVMFunctionType(int_type, NULL, 0, 0); + return LLVMAddFunction(module, name, function_type); +} + +static DISubprogramRef +create_function_with_entry(const char *name, int line) { + LLVMValueRef function = create_function(name); + LLVMBasicBlockRef bb = LLVMAppendBasicBlock(function, "entry"); + DISubprogramRef di_function = DICreateFunction(di_builder, di_compile_unit, name, name, file, line, + subroutine_type, 0, 1, 0); + LLVMPositionBuilderAtEnd(llvm_builder, bb); + DIFunctionAddSubprogram(function, di_function); + return di_function; +} + +static void +create_main() { + DISubprogramRef di = create_function_with_entry("main", 1); + LLVMValueRef address = LLVMBuildAlloca(llvm_builder, int_type, ""); + DILocationRef location = LLVMBuilderSetDebugLocation(llvm_builder, 2, 1, di); + DILocalVariableRef variable_a = DICreateAutoVariable(di_builder, di, "a", file, 2, di_int_type); + DIInsertDeclarationWithEmptyExpression(di_builder, address, variable_a, location, LLVMGetInsertBlock(llvm_builder)); + LLVMBuildStore(llvm_builder, LLVMConstInt(int_type, 42, 1), address); + LLVMValueRef value = LLVMBuildLoad(llvm_builder, address, ""); + LLVMBuildRet(llvm_builder, value); +} + + +int +main() { + module = LLVMModuleCreateWithName("test"); + di_builder = DICreateBuilder(module); + di_compile_unit = DICreateCompilationUnit(di_builder, 4, + "", "", + "konanc", 0, "", 0); + llvm_builder = LLVMCreateBuilderInContext(LLVMGetModuleContext(module)); + file = DICreateFile(di_builder, "", ""); + subroutine_type = DICreateSubroutineType(di_builder, NULL, 0); + int_type = LLVMInt32Type(); + di_int_type = DICreateBasicType(di_builder, "int", 32, 4, 0); + create_main(); + DIFinalize(di_builder); + + LLVMVerifyModule(module, LLVMPrintMessageAction, NULL); + LLVMDumpModule(module); + LLVMDisposeBuilder(llvm_builder); + LLVMDisposeModule(module); + LLVMShutdown(); +} diff --git a/llvmDebugInfoC/src/demo-simple/c/demo.c b/llvmDebugInfoC/src/demo-simple/c/demo.c new file mode 100644 index 00000000000..96ba09002f6 --- /dev/null +++ b/llvmDebugInfoC/src/demo-simple/c/demo.c @@ -0,0 +1,118 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +//clang llvmDebugInfoC/test/demo.c -IllvmDebugInfoC/include/ -Idependencies/all/clang+llvm-3.9.0-darwin-macos/include -c + +//c++ demo.o -Idependencies/all/clang+llvm-3.9.0-darwin-macos/include -Ldependencies/all/clang+llvm-3.9.0-darwin-macos/lib -lLLVMCore -lLLVMSupport -lncurses -o demo + +// +// 0:b-backend-dwarf:minamoto@unit-703(0)# clang -S -xc -emit-llvm -g -o - - +// int foo(int i) { return i; } +// int main() { +// int i = 0; +// return foo(i); +// } +// ; ModuleID = '-' +// source_filename = "-" +// target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +// target triple = "x86_64-apple-macosx10.12.0" +// +// ; Function Attrs: nounwind ssp uwtable +// define i32 @foo(i32) #0 !dbg !7 { +// %2 = alloca i32, align 4 +// store i32 %0, i32* %2, align 4 +// call void @llvm.dbg.declare(metadata i32* %2, metadata !12, metadata !13), !dbg !14 +// %3 = load i32, i32* %2, align 4, !dbg !15 +// ret i32 %3, !dbg !16 +// } +// +// ; Function Attrs: nounwind readnone +// declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 +// +// ; Function Attrs: nounwind ssp uwtable +// define i32 @main() #0 !dbg !17 { +// %1 = alloca i32, align 4 +// %2 = alloca i32, align 4 +// store i32 0, i32* %1, align 4 +// call void @llvm.dbg.declare(metadata i32* %2, metadata !20, metadata !13), !dbg !21 +// store i32 0, i32* %2, align 4, !dbg !21 +// %3 = load i32, i32* %2, align 4, !dbg !22 +// %4 = call i32 @foo(i32 %3), !dbg !23 +// ret i32 %4, !dbg !24 +// } +// +// attributes #0 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } +// attributes #1 = { nounwind readnone } +// +// !llvm.dbg.cu = !{!0} +// !llvm.module.flags = !{!3, !4, !5} +// !llvm.ident = !{!6} +// +// !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "Apple LLVM version 8.0.0 (clang-800.0.42.1)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +// !1 = !DIFile(filename: "-", directory: "/Users/minamoto/ws/.git-trees/backend-dwarf") +// !2 = !{} +// !3 = !{i32 2, !"Dwarf Version", i32 2} +// !4 = !{i32 2, !"Debug Info Version", i32 700000003} +// !5 = !{i32 1, !"PIC Level", i32 2} +// !6 = !{!"Apple LLVM version 8.0.0 (clang-800.0.42.1)"} +// !7 = distinct !DISubprogram(name: "foo", scope: !8, file: !8, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +// !8 = !DIFile(filename: "", directory: "/Users/minamoto/ws/.git-trees/backend-dwarf") +// !9 = !DISubroutineType(types: !10) +// !10 = !{!11, !11} +// !11 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +// !12 = !DILocalVariable(name: "i", arg: 1, scope: !7, file: !8, line: 1, type: !11) +// !13 = !DIExpression() +// !14 = !DILocation(line: 1, column: 13, scope: !7) +// !15 = !DILocation(line: 1, column: 25, scope: !7) +// !16 = !DILocation(line: 1, column: 18, scope: !7) +// !17 = distinct !DISubprogram(name: "main", scope: !8, file: !8, line: 2, type: !18, isLocal: false, isDefinition: true, scopeLine: 2, isOptimized: false, unit: !0, variables: !2) +// !18 = !DISubroutineType(types: !19) +// !19 = !{!11} +// !20 = !DILocalVariable(name: "i", scope: !17, file: !8, line: 3, type: !11) +// !21 = !DILocation(line: 3, column: 7, scope: !17) +// !22 = !DILocation(line: 4, column: 14, scope: !17) +// !23 = !DILocation(line: 4, column: 10, scope: !17) +// !24 = !DILocation(line: 4, column: 3, scope: !17) + +int main() { + LLVMModuleRef module = LLVMModuleCreateWithName("test"); + DIBuilderRef builder = DICreateBuilder(module); + DIFileRef file = DICreateFile(builder, "1.kt", "src"); + DIModuleRef m = DICreateModule(builder, m, "a.out", "", "", ""); + DICompileUnitRef cu = DICreateCompilationUnit(builder, 4, "1.kt", "src", "konanc", 0, "", 0); + DIBasicTypeRef type0 = DICreateBasicType(builder, "int", 32, 4, 0); + DISubroutineTypeRef subroutineType = DICreateSubroutineType(builder, &type0, 1); + + const char *functionName = "foo"; + + DISubprogramRef diFunction = DICreateFunction(builder, cu, functionName, "foo:link", file, 66, subroutineType, 0, 1, 0); + + //function creation. + LLVMBuilderRef llvmBuilder = LLVMCreateBuilderInContext(LLVMGetModuleContext(module)); + LLVMTypeRef intType = LLVMInt32Type(); + LLVMValueRef functionType = LLVMFunctionType(intType, &intType, 1, 0); + LLVMValueRef llvmFunction = LLVMAddFunction(module, functionName, functionType); + DIFunctionAddSubprogram(llvmFunction, diFunction); + LLVMBasicBlockRef bb = LLVMAppendBasicBlock(llvmFunction, "entry"); + LLVMPositionBuilderAtEnd(llvmBuilder, bb); + LLVMBuilderSetDebugLocation(llvmBuilder, 42, 15, diFunction); + LLVMValueRef ret = LLVMBuildRet(llvmBuilder, LLVMGetParam(llvmFunction, 0)); + + DIFinalize(builder); + LLVMDumpModule(module); + return 0; +} diff --git a/llvmDebugInfoC/src/main/cpp/DebugInfoC.cpp b/llvmDebugInfoC/src/main/cpp/DebugInfoC.cpp new file mode 100644 index 00000000000..0d5633dbb29 --- /dev/null +++ b/llvmDebugInfoC/src/main/cpp/DebugInfoC.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "DebugInfoC.h" + + +/** + * c++ --std=c++11 llvmDebugInfoC/src/DebugInfoC.cpp -IllvmDebugInfoC/include/ -Idependencies/all/clang+llvm-3.9.0-darwin-macos/include -Ldependencies/all/clang+llvm-3.9.0-darwin-macos/lib -lLLVMCore -lLLVMSupport -lncurses -shared -o libLLVMDebugInfoC.dylib + */ + +namespace llvm { +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DIBuilder, DIBuilderRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DICompileUnit, DICompileUnitRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DIFile, DIFileRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DIBasicType, DIBasicTypeRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DIType, DITypeOpaqueRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DIModule, DIModuleRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DIScope, DIScopeOpaqueRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DISubroutineType, DISubroutineTypeRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DISubprogram, DISubprogramRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DILocation, DILocationRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DILocalVariable, DILocalVariableRef) +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DIExpression, DIExpressionRef) + +// from Module.cpp +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Module, LLVMModuleRef) +} + +extern "C" { + +DIBuilderRef DICreateBuilder(LLVMModuleRef module) { + return llvm::wrap(new llvm::DIBuilder(* llvm::unwrap(module))); +} + +void DIFinalize(DIBuilderRef builder) { + auto diBuilder = llvm::unwrap(builder); + diBuilder->finalize(); + delete diBuilder; +} + +DICompileUnitRef DICreateCompilationUnit(DIBuilderRef builder, unsigned int lang, + const char *file, const char* dir, + const char * producer, int isOptimized, + const char * flags, unsigned int rv) { + return llvm::wrap(llvm::unwrap(builder)->createCompileUnit(lang, file, dir, producer, isOptimized, flags, rv)); +} + +DIFileRef DICreateFile(DIBuilderRef builder, const char *filename, const char *directory) { + return llvm::wrap(llvm::unwrap(builder)->createFile(filename, directory)); +} + +DIBasicTypeRef DICreateBasicType(DIBuilderRef builder, const char* name, uint64_t sizeInBits, uint64_t alignment, unsigned encoding) { + return llvm::wrap(llvm::unwrap(builder)->createBasicType(name, sizeInBits, alignment, encoding)); +} + +DIModuleRef DICreateModule(DIBuilderRef builder, DIScopeOpaqueRef scope, + const char* name, const char* configurationMacro, + const char* includePath, const char *iSysRoot) { + return llvm::wrap(llvm::unwrap(builder)->createModule(llvm::unwrap(scope), name, configurationMacro, includePath, iSysRoot)); +} + +DISubprogramRef DICreateFunction(DIBuilderRef builder, DIScopeOpaqueRef scope, + const char* name, const char *linkageName, + DIFileRef file, unsigned lineNo, + DISubroutineTypeRef type, int isLocal, + int isDefinition, unsigned scopeLine) { + return llvm::wrap(llvm::unwrap(builder)->createFunction(llvm::unwrap(scope), + name, + linkageName, + llvm::unwrap(file), + lineNo, + llvm::unwrap(type), + isLocal, + isDefinition, + scopeLine)); +} + +/* */ +DISubroutineTypeRef DICreateSubroutineType(DIBuilderRef builder, + DITypeOpaqueRef* types, + unsigned typesCount) { + std::vector parameterTypes; + for (int i = 0; i != typesCount; ++i) { + parameterTypes.push_back(llvm::unwrap(types[i])); + } + llvm::DIBuilder *b = llvm::unwrap(builder); + llvm::DITypeRefArray typeArray = b->getOrCreateTypeArray(parameterTypes); + return llvm::wrap(b->createSubroutineType(typeArray)); +} + +void DIFunctionAddSubprogram(LLVMValueRef fn, DISubprogramRef sp) { + auto f = llvm::cast(llvm::unwrap(fn)); + auto dsp = llvm::cast(llvm::unwrap(sp)); + f->setSubprogram(dsp); + if (!dsp->describes(f)) { + fprintf(stderr, "error!!! f:%s, sp:%s\n", f->getName(), dsp->getLinkageName()); + } +} + +DILocalVariableRef DICreateAutoVariable(DIBuilderRef builder, DIScopeOpaqueRef scope, const char *name, DIFileRef file, unsigned line, DITypeOpaqueRef type) { + return llvm::wrap(llvm::unwrap(builder)->createAutoVariable( + llvm::unwrap(scope), + name, + llvm::unwrap(file), + line, + llvm::unwrap(type))); +} + +DIExpressionRef DICreateEmptyExpression(DIBuilderRef builder) { + return llvm::wrap(llvm::unwrap(builder)->createExpression()); +} + +void DIInsertDeclarationWithEmptyExpression(DIBuilderRef builder, LLVMValueRef value, DILocalVariableRef localVariable, DILocationRef location, LLVMBasicBlockRef bb) { + auto di_builder = llvm::unwrap(builder); + di_builder->insertDeclare(llvm::unwrap(value), + llvm::unwrap(localVariable), + di_builder->createExpression(), + llvm::unwrap(location), + llvm::unwrap(bb)); +} + +DILocationRef LLVMBuilderSetDebugLocation(LLVMBuilderRef builder, unsigned line, + unsigned col, DIScopeOpaqueRef scope) { + auto sp = llvm::unwrap(scope); + auto llvmBuilder = llvm::unwrap(builder); + auto location = llvm::DILocation::get(llvmBuilder->getContext(), line, col, sp, nullptr); + llvmBuilder->SetCurrentDebugLocation(location); + return llvm::wrap(location); +} + +void LLVMBuilderResetDebugLocation(LLVMBuilderRef builder) { + llvm::unwrap(builder)->SetCurrentDebugLocation(nullptr); +} + +LLVMValueRef LLVMBuilderGetCurrentFunction(LLVMBuilderRef builder) { + return llvm::wrap(llvm::unwrap(builder)->GetInsertBlock()->getParent()); +} + +const char* LLVMBuilderGetCurrentBbName(LLVMBuilderRef builder) { + return llvm::unwrap(builder)->GetInsertBlock()->getName().str().c_str(); +} + + +const char *DIGetSubprogramLinkName(DISubprogramRef sp) { + return llvm::unwrap(sp)->getLinkageName().str().c_str(); +} + +int DISubprogramDescribesFunction(DISubprogramRef sp, LLVMValueRef fn) { + return llvm::unwrap(sp)->describes(llvm::cast(llvm::unwrap(fn))); +} + +void DIScopeDump(DIScopeOpaqueRef scope) { + llvm::unwrap(scope)->dump(); +} +} /* extern "C" */ + diff --git a/llvmDebugInfoC/src/main/include/DebugInfoC.h b/llvmDebugInfoC/src/main/include/DebugInfoC.h new file mode 100644 index 00000000000..49f6b577208 --- /dev/null +++ b/llvmDebugInfoC/src/main/include/DebugInfoC.h @@ -0,0 +1,74 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DEBUG_INFO_C_H__ +# define __DEBUG_INFO_C_H__ +#include +# ifdef __cplusplus +extern "C" { +# endif +typedef struct DIBuilder *DIBuilderRef; +typedef struct DICompileUnit *DICompileUnitRef; +typedef struct DIFile *DIFileRef; +typedef struct DIBasicType *DIBasicTypeRef; +typedef struct DIType *DITypeOpaqueRef; +typedef struct DISubprogram *DISubprogramRef; +typedef struct DIModule *DIModuleRef; +typedef struct DIScope *DIScopeOpaqueRef; +typedef struct DISubroutineType *DISubroutineTypeRef; +typedef struct DISubprogram *DISubprogramRef; +typedef struct DILocation *DILocationRef; +typedef struct DILocalVariable *DILocalVariableRef; +typedef struct DIExpression *DIExpressionRef; + +DIBuilderRef DICreateBuilder(LLVMModuleRef module); +void DIFinalize(DIBuilderRef builder); + +DICompileUnitRef DICreateCompilationUnit(DIBuilderRef builder, unsigned int lang, const char *File, const char* dir, const char * producer, int isOptimized, const char * flags, unsigned int rv); + +DIFileRef DICreateFile(DIBuilderRef builder, const char *filename, const char *directory); + +DIBasicTypeRef DICreateBasicType(DIBuilderRef builder, const char* name, uint64_t sizeInBits, uint64_t alignment, unsigned encoding); + +DIModuleRef DICreateModule(DIBuilderRef builder, DIScopeOpaqueRef scope, + const char* name, const char* configurationMacro, + const char* includePath, const char *iSysRoot); + +DISubprogramRef DICreateFunction(DIBuilderRef builder, DIScopeOpaqueRef scope, + const char* name, const char *linkageName, + DIFileRef file, unsigned lineNo, + DISubroutineTypeRef type, int isLocal, + int isDefinition, unsigned scopeLine); + +DISubroutineTypeRef DICreateSubroutineType(DIBuilderRef builder, + DITypeOpaqueRef* types, + unsigned typesCount); + +DILocalVariableRef DICreateAutoVariable(DIBuilderRef builder, DIScopeOpaqueRef scope, const char *name, DIFileRef file, unsigned line, DITypeOpaqueRef type); +void DIInsertDeclarationWithEmptyExpression(DIBuilderRef builder, LLVMValueRef value, DILocalVariableRef localVariable, DILocationRef location, LLVMBasicBlockRef bb); +DIExpressionRef DICreateEmptyExpression(DIBuilderRef builder); +void DIFunctionAddSubprogram(LLVMValueRef fn, DISubprogramRef sp); +DILocationRef LLVMBuilderSetDebugLocation(LLVMBuilderRef builder, unsigned line, unsigned col, DIScopeOpaqueRef scope); +void LLVMBuilderResetDebugLocation(LLVMBuilderRef builder); +const char* LLVMBuilderGetCurrentBbName(LLVMBuilderRef builder); +const char *DIGetSubprogramLinkName(DISubprogramRef sp); +LLVMValueRef LLVMBuilderGetCurrentFunction(LLVMBuilderRef builder); +int DISubprogramDescribesFunction(DISubprogramRef sp, LLVMValueRef fn); +void DIScopeDump(DIScopeOpaqueRef scope); +# ifdef __cplusplus +} +# endif +#endif diff --git a/settings.gradle b/settings.gradle index d30f69357ab..2f723332cee 100644 --- a/settings.gradle +++ b/settings.gradle @@ -19,6 +19,7 @@ include ':Interop:Indexer' include ':Interop:StubGenerator' include ':Interop:Runtime' include ':InteropExample' +include ':llvmDebugInfoC' include ':backend.native' include ':runtime' include ':common'