Skip to content

Commit

Permalink
fix(debugging): don't create debug info for external functions/add LL…
Browse files Browse the repository at this point in the history
…VM-version-appropriate DI-metadata (PLC-lang#1072)

* fix(debugging): don't create debug info for external functions

* fix: debug info version, add separate args for overrides
  • Loading branch information
mhasel authored Feb 7, 2024
1 parent 6111391 commit eeb0bab
Show file tree
Hide file tree
Showing 43 changed files with 964 additions and 791 deletions.
98 changes: 93 additions & 5 deletions compiler/plc_driver/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub type ParameterError = clap::Error;
)]
#[clap(propagate_version = true)]
#[clap(subcommand_negates_reqs = true)]
#[clap(subcommand_precedence_over_arg = true)]
pub struct CompileParameters {
#[clap(short, long, global = true, name = "output-file", help = "Write output to <output-file>")]
pub output: Option<String>,
Expand Down Expand Up @@ -140,6 +141,32 @@ pub struct CompileParameters {
)]
pub generate_varinfo: bool,

#[clap(
name = "gdwarf",
long,
help = "Generate source-level debug information with the specified dwarf version",
value_name = "dwarf version",
global = true,
group = "dbg",
conflicts_with = "debug",
max_values = 1,
possible_values = &["2", "3", "4", "5"],
)]
pub gdwarf_version: Option<usize>,

#[clap(
name = "gdwarf-variables",
long,
help = "Generate debug information for global variables with the specified dwarf version",
value_name = "dwarf version",
global = true,
group = "dbg",
conflicts_with = "debug-variables",
max_values = 1,
possible_values = &["2", "3", "4", "5"],
)]
pub gdwarf_varinfo_version: Option<usize>,

#[clap(
name = "threads",
long,
Expand Down Expand Up @@ -274,12 +301,19 @@ impl CompileParameters {

pub fn debug_level(&self) -> DebugLevel {
if self.generate_debug {
DebugLevel::Full
} else if self.generate_varinfo {
DebugLevel::VariablesOnly
} else {
DebugLevel::None
return DebugLevel::Full(plc::DEFAULT_DWARF_VERSION);
}
if self.generate_varinfo {
return DebugLevel::VariablesOnly(plc::DEFAULT_DWARF_VERSION);
}
if let Some(version) = self.gdwarf_version {
return DebugLevel::Full(version);
}
if let Some(version) = self.gdwarf_varinfo_version {
return DebugLevel::VariablesOnly(version);
}

DebugLevel::None
}

// convert the scattered bools from structopt into an enum
Expand Down Expand Up @@ -762,4 +796,58 @@ mod cli_tests {
.to_string()
)
}

#[test]
fn test_gdwarf_and_debug_mutually_exclusive() {
assert!(CompileParameters::parse(vec_of_strings!("input.st", "--debug", "--gdwarf", "2")).is_err());
assert!(CompileParameters::parse(vec_of_strings!("input.st", "-g", "--gdwarf", "4")).is_err());
assert!(CompileParameters::parse(vec_of_strings!(
"input.st",
"--debug-variables",
"--gdwarf-variables",
"3"
))
.is_err());
}

#[test]
fn test_dwarf_version_override() {
let parameters = CompileParameters::parse(vec_of_strings!("input.st", "--gdwarf", "2")).unwrap();
assert_eq!(parameters.gdwarf_version, Some(2));

let parameters = CompileParameters::parse(vec_of_strings!("input.st", "--gdwarf", "3")).unwrap();
assert_eq!(parameters.gdwarf_version, Some(3));

let parameters =
CompileParameters::parse(vec_of_strings!("input.st", "--gdwarf-variables", "4")).unwrap();
assert_eq!(parameters.gdwarf_varinfo_version, Some(4));
}

#[test]
fn invalid_dwarf_version() {
let error = CompileParameters::parse(vec_of_strings!("input.st", "--gdwarf", "1")).unwrap_err();
assert_eq!(error.kind(), ErrorKind::InvalidValue);
let inner = &error.info;
assert_eq!(inner[1], "1");

let error =
CompileParameters::parse(vec_of_strings!("input.st", "--gdwarf-variables", "99")).unwrap_err();
assert_eq!(error.kind(), ErrorKind::InvalidValue);
let inner = &error.info;
assert_eq!(inner[1], "99");

let error = CompileParameters::parse(vec_of_strings!("input.st", "--gdwarf", "abc")).unwrap_err();
assert_eq!(error.kind(), ErrorKind::InvalidValue);
let inner = &error.info;
assert_eq!(inner[1], "abc");
}

#[test]
fn dwarf_version_override_arg_requries_value() {
let error = CompileParameters::parse(vec_of_strings!("input.st", "--gdwarf")).unwrap_err();
assert_eq!(error.kind(), ErrorKind::EmptyValue);

let error = CompileParameters::parse(vec_of_strings!("input.st", "--gdwarf-variables")).unwrap_err();
assert_eq!(error.kind(), ErrorKind::EmptyValue);
}
}
2 changes: 1 addition & 1 deletion compiler/plc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ fn generate_to_string_internal<T: SourceContainer>(
let context = CodegenContext::create();
let mut options = CompileOptions::default();
if debug {
options.debug_level = DebugLevel::Full;
options.debug_level = DebugLevel::Full(plc::DEFAULT_DWARF_VERSION);
}
let module = project.generate_single_module(&context, &options)?;

Expand Down
8 changes: 6 additions & 2 deletions compiler/plc_driver/src/tests/multi_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ fn multiple_files_with_debug_info() {
"file2.st",
);
//When the are generated
let results = compile_with_root(vec![src1, src2], vec![], "root", DebugLevel::Full).unwrap();
let results =
compile_with_root(vec![src1, src2], vec![], "root", DebugLevel::Full(plc::DEFAULT_DWARF_VERSION))
.unwrap();
assert_eq!(results.len(), 2);
//The datatypes do not conflics
//The functions are defined correctly
Expand Down Expand Up @@ -106,7 +108,9 @@ fn multiple_files_in_different_locations_with_debug_info() {
"lib/file2.st",
);
//When the are generated
let results = compile_with_root(vec![src1, src2], vec![], "root", DebugLevel::Full).unwrap();
let results =
compile_with_root(vec![src1, src2], vec![], "root", DebugLevel::Full(plc::DEFAULT_DWARF_VERSION))
.unwrap();
assert_eq!(results.len(), 2);
//The datatypes do not conflics
//The functions are defined correctly
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,45 @@ source_filename = "app/file1.st"

@mainProg_instance = external global %mainProg, !dbg !0

define i16 @main() !dbg !9 {
define i16 @main() !dbg !10 {
entry:
%main = alloca i16, align 2, !dbg !13
call void @llvm.dbg.declare(metadata i16* %main, metadata !14, metadata !DIExpression()), !dbg !16
store i16 0, i16* %main, align 2, !dbg !13
call void @mainProg(%mainProg* @mainProg_instance), !dbg !13
%main_ret = load i16, i16* %main, align 2, !dbg !13
ret i16 %main_ret, !dbg !13
%main = alloca i16, align 2, !dbg !14
call void @llvm.dbg.declare(metadata i16* %main, metadata !15, metadata !DIExpression()), !dbg !17
store i16 0, i16* %main, align 2, !dbg !14
call void @mainProg(%mainProg* @mainProg_instance), !dbg !14
%main_ret = load i16, i16* %main, align 2, !dbg !14
ret i16 %main_ret, !dbg !14
}

declare !dbg !17 void @mainProg(%mainProg*)
declare !dbg !18 void @mainProg(%mainProg*)

; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0

attributes #0 = { nofree nosync nounwind readnone speculatable willreturn }

!llvm.module.flags = !{!5}
!llvm.dbg.cu = !{!6}
!llvm.module.flags = !{!5, !6}
!llvm.dbg.cu = !{!7}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "mainProg", scope: !2, file: !2, line: 2, type: !3, isLocal: false, isDefinition: true)
!2 = !DIFile(filename: "file2.st", directory: "lib")
!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "mainProg", scope: !2, file: !2, line: 2, align: 64, flags: DIFlagPublic, elements: !4, identifier: "mainProg")
!4 = !{}
!5 = !{i32 2, !"Dwarf Version", i32 5}
!6 = distinct !DICompileUnit(language: DW_LANG_C, file: !7, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !8, splitDebugInlining: false)
!7 = !DIFile(filename: "app/file1.st", directory: "root")
!8 = !{!0}
!9 = distinct !DISubprogram(name: "main", linkageName: "main", scope: !10, file: !10, line: 2, type: !11, scopeLine: 10, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !4)
!10 = !DIFile(filename: "file1.st", directory: "app")
!11 = !DISubroutineType(flags: DIFlagPublic, types: !12)
!12 = !{null}
!13 = !DILocation(line: 10, column: 4, scope: !9)
!14 = !DILocalVariable(name: "main", scope: !9, file: !10, line: 2, type: !15, align: 16)
!15 = !DIBasicType(name: "INT", size: 16, encoding: DW_ATE_signed, flags: DIFlagPublic)
!16 = !DILocation(line: 2, column: 13, scope: !9)
!17 = distinct !DISubprogram(name: "mainProg", linkageName: "mainProg", scope: !2, file: !2, line: 2, type: !11, scopeLine: 5, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !4)
!6 = !{i32 2, !"Debug Info Version", i32 3}
!7 = distinct !DICompileUnit(language: DW_LANG_C, file: !8, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !9, splitDebugInlining: false)
!8 = !DIFile(filename: "app/file1.st", directory: "root")
!9 = !{!0}
!10 = distinct !DISubprogram(name: "main", linkageName: "main", scope: !11, file: !11, line: 2, type: !12, scopeLine: 10, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !4)
!11 = !DIFile(filename: "file1.st", directory: "app")
!12 = !DISubroutineType(flags: DIFlagPublic, types: !13)
!13 = !{null}
!14 = !DILocation(line: 10, column: 4, scope: !10)
!15 = !DILocalVariable(name: "main", scope: !10, file: !11, line: 2, type: !16, align: 16)
!16 = !DIBasicType(name: "INT", size: 16, encoding: DW_ATE_signed, flags: DIFlagPublic)
!17 = !DILocation(line: 2, column: 13, scope: !10)
!18 = distinct !DISubprogram(name: "mainProg", linkageName: "mainProg", scope: !2, file: !2, line: 2, type: !12, scopeLine: 5, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !4)

; ModuleID = 'lib/file2.st'
source_filename = "lib/file2.st"
Expand All @@ -55,32 +56,33 @@ source_filename = "lib/file2.st"

@mainProg_instance = global %mainProg zeroinitializer, !dbg !0

define void @mainProg(%mainProg* %0) !dbg !9 {
define void @mainProg(%mainProg* %0) !dbg !10 {
entry:
call void @llvm.dbg.declare(metadata %mainProg* %0, metadata !12, metadata !DIExpression()), !dbg !13
ret void, !dbg !13
call void @llvm.dbg.declare(metadata %mainProg* %0, metadata !13, metadata !DIExpression()), !dbg !14
ret void, !dbg !14
}

; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0

attributes #0 = { nofree nosync nounwind readnone speculatable willreturn }

!llvm.module.flags = !{!5}
!llvm.dbg.cu = !{!6}
!llvm.module.flags = !{!5, !6}
!llvm.dbg.cu = !{!7}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "mainProg", scope: !2, file: !2, line: 2, type: !3, isLocal: false, isDefinition: true)
!2 = !DIFile(filename: "file2.st", directory: "lib")
!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "mainProg", scope: !2, file: !2, line: 2, align: 64, flags: DIFlagPublic, elements: !4, identifier: "mainProg")
!4 = !{}
!5 = !{i32 2, !"Dwarf Version", i32 5}
!6 = distinct !DICompileUnit(language: DW_LANG_C, file: !7, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !8, splitDebugInlining: false)
!7 = !DIFile(filename: "lib/file2.st", directory: "root")
!8 = !{!0}
!9 = distinct !DISubprogram(name: "mainProg", linkageName: "mainProg", scope: !2, file: !2, line: 2, type: !10, scopeLine: 5, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !4)
!10 = !DISubroutineType(flags: DIFlagPublic, types: !11)
!11 = !{null}
!12 = !DILocalVariable(name: "mainProg", scope: !9, file: !2, line: 2, type: !3)
!13 = !DILocation(line: 5, column: 4, scope: !9)
!6 = !{i32 2, !"Debug Info Version", i32 3}
!7 = distinct !DICompileUnit(language: DW_LANG_C, file: !8, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !9, splitDebugInlining: false)
!8 = !DIFile(filename: "lib/file2.st", directory: "root")
!9 = !{!0}
!10 = distinct !DISubprogram(name: "mainProg", linkageName: "mainProg", scope: !2, file: !2, line: 2, type: !11, scopeLine: 5, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !4)
!11 = !DISubroutineType(flags: DIFlagPublic, types: !12)
!12 = !{null}
!13 = !DILocalVariable(name: "mainProg", scope: !10, file: !2, line: 2, type: !3)
!14 = !DILocation(line: 5, column: 4, scope: !10)

Original file line number Diff line number Diff line change
Expand Up @@ -9,44 +9,45 @@ source_filename = "file1.st"

@mainProg_instance = external global %mainProg, !dbg !0

define i16 @main() !dbg !9 {
define i16 @main() !dbg !10 {
entry:
%main = alloca i16, align 2, !dbg !13
call void @llvm.dbg.declare(metadata i16* %main, metadata !14, metadata !DIExpression()), !dbg !16
store i16 0, i16* %main, align 2, !dbg !13
call void @mainProg(%mainProg* @mainProg_instance), !dbg !13
%main_ret = load i16, i16* %main, align 2, !dbg !13
ret i16 %main_ret, !dbg !13
%main = alloca i16, align 2, !dbg !14
call void @llvm.dbg.declare(metadata i16* %main, metadata !15, metadata !DIExpression()), !dbg !17
store i16 0, i16* %main, align 2, !dbg !14
call void @mainProg(%mainProg* @mainProg_instance), !dbg !14
%main_ret = load i16, i16* %main, align 2, !dbg !14
ret i16 %main_ret, !dbg !14
}

declare !dbg !17 void @mainProg(%mainProg*)
declare !dbg !18 void @mainProg(%mainProg*)

; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0

attributes #0 = { nofree nosync nounwind readnone speculatable willreturn }

!llvm.module.flags = !{!5}
!llvm.dbg.cu = !{!6}
!llvm.module.flags = !{!5, !6}
!llvm.dbg.cu = !{!7}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "mainProg", scope: !2, file: !2, line: 2, type: !3, isLocal: false, isDefinition: true)
!2 = !DIFile(filename: "file2.st", directory: "")
!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "mainProg", scope: !2, file: !2, line: 2, align: 64, flags: DIFlagPublic, elements: !4, identifier: "mainProg")
!4 = !{}
!5 = !{i32 2, !"Dwarf Version", i32 5}
!6 = distinct !DICompileUnit(language: DW_LANG_C, file: !7, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !8, splitDebugInlining: false)
!7 = !DIFile(filename: "file1.st", directory: "root")
!8 = !{!0}
!9 = distinct !DISubprogram(name: "main", linkageName: "main", scope: !10, file: !10, line: 2, type: !11, scopeLine: 10, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !4)
!10 = !DIFile(filename: "file1.st", directory: "")
!11 = !DISubroutineType(flags: DIFlagPublic, types: !12)
!12 = !{null}
!13 = !DILocation(line: 10, column: 4, scope: !9)
!14 = !DILocalVariable(name: "main", scope: !9, file: !10, line: 2, type: !15, align: 16)
!15 = !DIBasicType(name: "INT", size: 16, encoding: DW_ATE_signed, flags: DIFlagPublic)
!16 = !DILocation(line: 2, column: 13, scope: !9)
!17 = distinct !DISubprogram(name: "mainProg", linkageName: "mainProg", scope: !2, file: !2, line: 2, type: !11, scopeLine: 5, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !4)
!6 = !{i32 2, !"Debug Info Version", i32 3}
!7 = distinct !DICompileUnit(language: DW_LANG_C, file: !8, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !9, splitDebugInlining: false)
!8 = !DIFile(filename: "file1.st", directory: "root")
!9 = !{!0}
!10 = distinct !DISubprogram(name: "main", linkageName: "main", scope: !11, file: !11, line: 2, type: !12, scopeLine: 10, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !4)
!11 = !DIFile(filename: "file1.st", directory: "")
!12 = !DISubroutineType(flags: DIFlagPublic, types: !13)
!13 = !{null}
!14 = !DILocation(line: 10, column: 4, scope: !10)
!15 = !DILocalVariable(name: "main", scope: !10, file: !11, line: 2, type: !16, align: 16)
!16 = !DIBasicType(name: "INT", size: 16, encoding: DW_ATE_signed, flags: DIFlagPublic)
!17 = !DILocation(line: 2, column: 13, scope: !10)
!18 = distinct !DISubprogram(name: "mainProg", linkageName: "mainProg", scope: !2, file: !2, line: 2, type: !12, scopeLine: 5, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !4)

; ModuleID = 'file2.st'
source_filename = "file2.st"
Expand All @@ -55,32 +56,33 @@ source_filename = "file2.st"

@mainProg_instance = global %mainProg zeroinitializer, !dbg !0

define void @mainProg(%mainProg* %0) !dbg !9 {
define void @mainProg(%mainProg* %0) !dbg !10 {
entry:
call void @llvm.dbg.declare(metadata %mainProg* %0, metadata !12, metadata !DIExpression()), !dbg !13
ret void, !dbg !13
call void @llvm.dbg.declare(metadata %mainProg* %0, metadata !13, metadata !DIExpression()), !dbg !14
ret void, !dbg !14
}

; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare void @llvm.dbg.declare(metadata, metadata, metadata) #0

attributes #0 = { nofree nosync nounwind readnone speculatable willreturn }

!llvm.module.flags = !{!5}
!llvm.dbg.cu = !{!6}
!llvm.module.flags = !{!5, !6}
!llvm.dbg.cu = !{!7}

!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
!1 = distinct !DIGlobalVariable(name: "mainProg", scope: !2, file: !2, line: 2, type: !3, isLocal: false, isDefinition: true)
!2 = !DIFile(filename: "file2.st", directory: "")
!3 = !DICompositeType(tag: DW_TAG_structure_type, name: "mainProg", scope: !2, file: !2, line: 2, align: 64, flags: DIFlagPublic, elements: !4, identifier: "mainProg")
!4 = !{}
!5 = !{i32 2, !"Dwarf Version", i32 5}
!6 = distinct !DICompileUnit(language: DW_LANG_C, file: !7, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !8, splitDebugInlining: false)
!7 = !DIFile(filename: "file2.st", directory: "root")
!8 = !{!0}
!9 = distinct !DISubprogram(name: "mainProg", linkageName: "mainProg", scope: !2, file: !2, line: 2, type: !10, scopeLine: 5, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !4)
!10 = !DISubroutineType(flags: DIFlagPublic, types: !11)
!11 = !{null}
!12 = !DILocalVariable(name: "mainProg", scope: !9, file: !2, line: 2, type: !3)
!13 = !DILocation(line: 5, column: 4, scope: !9)
!6 = !{i32 2, !"Debug Info Version", i32 3}
!7 = distinct !DICompileUnit(language: DW_LANG_C, file: !8, producer: "RuSTy Structured text Compiler", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !9, splitDebugInlining: false)
!8 = !DIFile(filename: "file2.st", directory: "root")
!9 = !{!0}
!10 = distinct !DISubprogram(name: "mainProg", linkageName: "mainProg", scope: !2, file: !2, line: 2, type: !11, scopeLine: 5, flags: DIFlagPublic, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !4)
!11 = !DISubroutineType(flags: DIFlagPublic, types: !12)
!12 = !{null}
!13 = !DILocalVariable(name: "mainProg", scope: !10, file: !2, line: 2, type: !3)
!14 = !DILocation(line: 5, column: 4, scope: !10)

Loading

0 comments on commit eeb0bab

Please sign in to comment.