From 9bfcf36016c5ce585e0f6f561e1629e3f551f019 Mon Sep 17 00:00:00 2001 From: ychenfo Date: Thu, 14 Apr 2022 15:40:12 +0800 Subject: [PATCH] nac3core: add debug info --- nac3core/src/codegen/expr.rs | 11 +++++ nac3core/src/codegen/mod.rs | 85 +++++++++++++++++++++++++++++++++++- nac3core/src/codegen/stmt.rs | 11 +++++ 3 files changed, 106 insertions(+), 1 deletion(-) diff --git a/nac3core/src/codegen/expr.rs b/nac3core/src/codegen/expr.rs index 3ca72835..6d4f70ef 100644 --- a/nac3core/src/codegen/expr.rs +++ b/nac3core/src/codegen/expr.rs @@ -14,6 +14,7 @@ use crate::{ }; use inkwell::{ AddressSpace, + debug_info::AsDIScope, attributes::{Attribute, AttributeLoc}, types::{AnyType, BasicType, BasicTypeEnum}, values::{BasicValueEnum, FunctionValue, IntValue, PointerValue} @@ -969,6 +970,16 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator>( ctx.current_loc = expr.location; let int32 = ctx.ctx.i32_type(); let zero = int32.const_int(0, false); + + let loc = ctx.debug_info.0.create_debug_location( + ctx.ctx, + ctx.current_loc.row as u32, + ctx.current_loc.column as u32, + ctx.debug_info.2.as_debug_info_scope(), + None, + ); + ctx.builder.set_current_debug_location(ctx.ctx, loc); + Ok(Some(match &expr.node { ExprKind::Constant { value, .. } => { let ty = expr.custom.unwrap(); diff --git a/nac3core/src/codegen/mod.rs b/nac3core/src/codegen/mod.rs index 191b023e..75899db0 100644 --- a/nac3core/src/codegen/mod.rs +++ b/nac3core/src/codegen/mod.rs @@ -17,7 +17,10 @@ use inkwell::{ module::Module, passes::{PassManager, PassManagerBuilder}, types::{AnyType, BasicType, BasicTypeEnum}, - values::{BasicValueEnum, FunctionValue, PhiValue, PointerValue} + values::{BasicValueEnum, FunctionValue, PhiValue, PointerValue}, + debug_info::{ + DebugInfoBuilder, DICompileUnit, DISubprogram, AsDIScope, DIFlagsConstants, DILexicalBlock + }, }; use itertools::Itertools; use nac3parser::ast::{Stmt, StrRef, Location}; @@ -52,6 +55,7 @@ pub type VarValue<'ctx> = (PointerValue<'ctx>, Option { pub ctx: &'ctx Context, pub builder: Builder<'ctx>, + pub debug_info: (DebugInfoBuilder<'ctx>, DICompileUnit<'ctx>, DILexicalBlock<'ctx>), pub module: Module<'ctx>, pub top_level: &'a TopLevelContext, pub unifier: Unifier, @@ -203,6 +207,17 @@ impl WorkerRegistry { let mut builder = context.create_builder(); let module = context.create_module(generator.get_name()); + module.add_basic_value_flag( + "Debug Info Version", + inkwell::module::FlagBehavior::Warning, + context.i32_type().const_int(3, false), + ); + module.add_basic_value_flag( + "Dwarf Version", + inkwell::module::FlagBehavior::Warning, + context.i32_type().const_int(4, false), + ); + let pass_builder = PassManagerBuilder::create(); pass_builder.set_optimization_level(OptimizationLevel::Default); let passes = PassManager::create(&module); @@ -551,6 +566,61 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte builder.build_unconditional_branch(body_bb); builder.position_at_end(body_bb); + let (dibuilder, compile_unit) = module.create_debug_info_builder( + /* allow_unresolved */ true, + /* language */ inkwell::debug_info::DWARFSourceLanguage::Python, + /* filename */ + &task + .body + .get(0) + .map_or_else(|| "_nac3_internal".to_string(), |f| f.location.file.0.to_string()), + /* directory */ ".", + /* producer */ "NAC3", + /* is_optimized */ false, + /* compiler command line flags */ "", + /* runtime_ver */ 0, + /* split_name */ "", + /* kind */ inkwell::debug_info::DWARFEmissionKind::LineTablesOnly, + /* dwo_id */ 0, + /* split_debug_inling */ false, + /* debug_info_for_profiling */ false, + /* sysroot */ "", + /* sdk */ "", + ); + let subroutine_type = dibuilder.create_subroutine_type( + compile_unit.get_file(), + Some( + dibuilder + .create_basic_type("_", 0_u64, 0x00, inkwell::debug_info::DIFlags::PUBLIC) + .unwrap() + .as_type(), + ), + &[], + inkwell::debug_info::DIFlags::PUBLIC, + ); + let func_scope: DISubprogram<'_> = dibuilder.create_function( + /* scope */ compile_unit.as_debug_info_scope(), + /* func name */ symbol, + /* linkage_name */ None, + /* file */ compile_unit.get_file(), + /* line_no */ 0, + /* DIType */ subroutine_type, + /* is_local_to_unit */ true, + /* is_definition */ true, + /* scope_line */ 0, + /* flags */ inkwell::debug_info::DIFlags::PUBLIC, + /* is_optimized */ false, + ); + fn_val.set_subprogram(func_scope); + let (row, col) = + task.body.get(0).map_or_else(|| (0, 0), |b| (b.location.row, b.location.column)); + let lexical_block = dibuilder.create_lexical_block( + /* scope */ func_scope.as_debug_info_scope(), + /* file */ compile_unit.get_file(), + /* line_no */ row as u32, + /* column_no */ col as u32, + ); + let mut code_gen_context = CodeGenContext { ctx: context, resolver: task.resolver, @@ -573,8 +643,18 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte static_value_store, need_sret: has_sret, current_loc: Default::default(), + debug_info: (dibuilder, compile_unit, lexical_block), }; + let loc = code_gen_context.debug_info.0.create_debug_location( + context, + row as u32, + col as u32, + lexical_block.as_debug_info_scope(), + None + ); + code_gen_context.builder.set_current_debug_location(context, loc); + let result = codegen_function(generator, &mut code_gen_context); // after static analysis, only void functions can have no return at the end. @@ -582,6 +662,9 @@ pub fn gen_func_impl<'ctx, G: CodeGenerator, F: FnOnce(&mut G, &mut CodeGenConte code_gen_context.builder.build_return(None); } + code_gen_context.builder.unset_current_debug_location(); + code_gen_context.debug_info.0.finalize(); + let CodeGenContext { builder, module, .. } = code_gen_context; if let Err(e) = result { return Err((builder, e)); diff --git a/nac3core/src/codegen/stmt.rs b/nac3core/src/codegen/stmt.rs index 9209440d..29328807 100644 --- a/nac3core/src/codegen/stmt.rs +++ b/nac3core/src/codegen/stmt.rs @@ -11,6 +11,7 @@ use crate::{ }; use inkwell::{ attributes::{Attribute, AttributeLoc}, + debug_info::AsDIScope, basic_block::BasicBlock, types::BasicTypeEnum, values::{BasicValue, BasicValueEnum, FunctionValue, PointerValue}, @@ -989,6 +990,16 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator>( stmt: &Stmt>, ) -> Result<(), String> { ctx.current_loc = stmt.location; + + let loc = ctx.debug_info.0.create_debug_location( + ctx.ctx, + ctx.current_loc.row as u32, + ctx.current_loc.column as u32, + ctx.debug_info.2.as_debug_info_scope(), + None, + ); + ctx.builder.set_current_debug_location(ctx.ctx, loc); + match &stmt.node { StmtKind::Pass { .. } => {} StmtKind::Expr { value, .. } => {