diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 289bb4f63f59..ece0c1cb1909 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -224,13 +224,51 @@ pub type SectionIteratorRef = *SectionIterator_opaque; pub enum Pass_opaque {} pub type PassRef = *Pass_opaque; +pub mod debuginfo { + use core::prelude::*; + use super::{ValueRef}; + + pub enum DIBuilder_opaque {} + pub type DIBuilderRef = *DIBuilder_opaque; + + pub type DIDescriptor = ValueRef; + pub type DIScope = DIDescriptor; + pub type DILocation = DIDescriptor; + pub type DIFile = DIScope; + pub type DILexicalBlock = DIScope; + pub type DISubprogram = DIScope; + pub type DIType = DIDescriptor; + pub type DIBasicType = DIType; + pub type DIDerivedType = DIType; + pub type DICompositeType = DIDerivedType; + pub type DIVariable = DIDescriptor; + pub type DIArray = DIDescriptor; + pub type DISubrange = DIDescriptor; + + pub enum DIDescriptorFlags { + FlagPrivate = 1 << 0, + FlagProtected = 1 << 1, + FlagFwdDecl = 1 << 2, + FlagAppleBlock = 1 << 3, + FlagBlockByrefStruct = 1 << 4, + FlagVirtual = 1 << 5, + FlagArtificial = 1 << 6, + FlagExplicit = 1 << 7, + FlagPrototyped = 1 << 8, + FlagObjcClassComplete = 1 << 9, + FlagObjectPointer = 1 << 10, + FlagVector = 1 << 11, + FlagStaticMember = 1 << 12 + } +} + pub mod llvm { use super::{AtomicBinOp, AtomicOrdering, BasicBlockRef, ExecutionEngineRef}; use super::{Bool, BuilderRef, ContextRef, MemoryBufferRef, ModuleRef}; use super::{ObjectFileRef, Opcode, PassManagerRef, PassManagerBuilderRef}; use super::{SectionIteratorRef, TargetDataRef, TypeKind, TypeRef, UseRef}; - use super::{ValueRef,PassRef}; - + use super::{ValueRef, PassRef}; + use super::debuginfo::*; use core::libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong}; #[link_args = "-Lrustllvm -lrustllvm"] @@ -1885,6 +1923,149 @@ pub mod llvm { AlignStack: Bool, Dialect: c_uint) -> ValueRef; + + #[fast_ffi] + pub unsafe fn DIBuilder_new(M: ModuleRef) -> DIBuilderRef; + + #[fast_ffi] + pub unsafe fn DIBuilder_delete(Builder: DIBuilderRef); + + #[fast_ffi] + pub unsafe fn DIBuilder_finalize(Builder: DIBuilderRef); + + #[fast_ffi] + pub unsafe fn DIBuilder_createCompileUnit( + Builder: DIBuilderRef, + Lang: c_uint, + File: *c_char, + Dir: *c_char, + Producer: *c_char, + isOptimized: bool, + Flags: *c_char, + RuntimeVer: c_uint, + SplitName: *c_char); + + #[fast_ffi] + pub unsafe fn DIBuilder_createFile( + Builder: DIBuilderRef, + Filename: *c_char, + Directory: *c_char) -> DIFile; + + #[fast_ffi] + pub unsafe fn DIBuilder_createSubroutineType( + Builder: DIBuilderRef, + File: DIFile, + ParameterTypes: DIArray) -> DICompositeType; + + #[fast_ffi] + pub unsafe fn DIBuilder_createFunction( + Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *c_char, + LinkageName: *c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + isLocalToUnit: bool, + isDefinition: bool, + ScopeLine: c_uint, + Flags: c_uint, + isOptimized: bool, + Fn: ValueRef, + TParam: ValueRef, + Decl: ValueRef) -> DISubprogram; + + #[fast_ffi] + pub unsafe fn DIBuilder_createBasicType( + Builder: DIBuilderRef, + Name: *c_char, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + Encoding: c_uint) -> DIBasicType; + + #[fast_ffi] + pub unsafe fn DIBuilder_createPointerType( + Builder: DIBuilderRef, + PointeeTy: DIType, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + Name: *c_char) -> DIDerivedType; + + #[fast_ffi] + pub unsafe fn DIBuilder_createStructType( + Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *c_char, + File: DIFile, + LineNumber: c_uint, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + Flags: c_uint, + DerivedFrom: DIType, + Elements: DIArray, + RunTimeLang: c_uint, + VTableHolder: ValueRef) -> DICompositeType; + + #[fast_ffi] + pub unsafe fn DIBuilder_createMemberType( + Builder: DIBuilderRef, + Scope: DIDescriptor, + Name: *c_char, + File: DIFile, + LineNo: c_uint, + SizeInBits: c_ulonglong, + AlignInBits: c_ulonglong, + OffsetInBits: c_ulonglong, + Flags: c_uint, + Ty: DIType) -> DIDerivedType; + + #[fast_ffi] + pub unsafe fn DIBuilder_createLexicalBlock( + Builder: DIBuilderRef, + Scope: DIDescriptor, + File: DIFile, + Line: c_uint, + Col: c_uint) -> DILexicalBlock; + + #[fast_ffi] + pub unsafe fn DIBuilder_createLocalVariable( + Builder: DIBuilderRef, + Tag: c_uint, + Scope: DIDescriptor, + Name: *c_char, + File: DIFile, + LineNo: c_uint, + Ty: DIType, + AlwaysPreserve: bool, + Flags: c_uint, + ArgNo: c_uint) -> DIVariable; + + #[fast_ffi] + pub unsafe fn DIBuilder_createVectorType( + Builder: DIBuilderRef, + Size: c_ulonglong, + AlignInBits: c_ulonglong, + Ty: DIType, + Subscripts: DIArray) -> DIType; + + #[fast_ffi] + pub unsafe fn DIBuilder_getOrCreateSubrange( + Builder: DIBuilderRef, + Lo: c_longlong, + Count: c_longlong) -> DISubrange; + + #[fast_ffi] + pub unsafe fn DIBuilder_getOrCreateArray( + Builder: DIBuilderRef, + Ptr: *DIDescriptor, + Count: c_uint) -> DIArray; + + #[fast_ffi] + pub unsafe fn DIBuilder_insertDeclare( + Builder: DIBuilderRef, + Val: ValueRef, + VarInfo: DIVariable, + InsertBefore: *c_void) -> *c_void; } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 53f2729c38e9..580e7fa1900a 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -3074,6 +3074,7 @@ pub fn trans_crate(sess: session::Session, // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 let llmod_id = link_meta.name.to_owned() + ".rc"; + Some(debuginfo::mk_ctxt(llmod, copy llmod_id)) // FIXME(#6511): get LLVM building with --enable-threads so this // function can be called // if !llvm::LLVMRustStartMultithreading() { @@ -3102,7 +3103,10 @@ pub fn trans_crate(sess: session::Session, fill_crate_map(ccx, ccx.crate_map); glue::emit_tydescs(ccx); write_abi_version(ccx); - + if ccx.sess.opts.debuginfo { + debuginfo::finalize(ccx); + } + // Translate the metadata. write_metadata(ccx, crate); if ccx.sess.trans_stats() { diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 87c33ce64f54..a01c2b89bf9d 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -11,9 +11,9 @@ use core::prelude::*; use driver::session; -use lib::llvm::ValueRef; use lib::llvm::llvm; -use middle::trans::context::task_llcx; +use lib::llvm::{ValueRef, ModuleRef, ContextRef}; +use lib::llvm::debuginfo::*; use middle::trans::common::*; use middle::trans::machine; use middle::trans::type_of; @@ -21,21 +21,17 @@ use middle::trans; use middle::ty; use util::ppaux::ty_to_str; -use core::cast; use core::hashmap::HashMap; use core::libc; -use core::option; -use core::ptr; -use core::str; -use core::sys; -use core::vec; +use core::libc::c_uint; +use core::str::as_c_str; use syntax::codemap::span; +use syntax::parse::token::ident_interner; use syntax::{ast, codemap, ast_util, ast_map}; -static LLVMDebugVersion: int = (9 << 16); +static LLVMDebugVersion: int = (12 << 16); -static DW_LANG_RUST: int = 0x9000; -static DW_VIRTUALITY_none: int = 0; +static DW_LANG_RUST: int = 12; //0x9000; static CompileUnitTag: int = 17; static FileDescriptorTag: int = 41; @@ -59,302 +55,185 @@ static DW_ATE_signed_char: int = 0x06; static DW_ATE_unsigned: int = 0x07; static DW_ATE_unsigned_char: int = 0x08; -fn llstr(s: &str) -> ValueRef { - do str::as_c_str(s) |sbuf| { - unsafe { - llvm::LLVMMDStringInContext(task_llcx(), - sbuf, - s.len() as libc::c_uint) - } - } -} -fn lltag(lltag: int) -> ValueRef { - lli32(LLVMDebugVersion | lltag) -} -fn lli32(val: int) -> ValueRef { - C_i32(val as i32) -} -fn lli64(val: int) -> ValueRef { - C_i64(val as i64) -} -fn lli1(bval: bool) -> ValueRef { - C_i1(bval) -} -fn llmdnode(elems: &[ValueRef]) -> ValueRef { - unsafe { - llvm::LLVMMDNodeInContext(task_llcx(), - vec::raw::to_ptr(elems), - elems.len() as libc::c_uint) - } -} -fn llunused() -> ValueRef { - lli32(0x0) -} -fn llnull() -> ValueRef { - unsafe { - cast::transmute(ptr::null::()) - } -} - -fn add_named_metadata(cx: &CrateContext, name: ~str, val: ValueRef) { - str::as_c_str(name, |sbuf| { - unsafe { - llvm::LLVMAddNamedMetadataOperand(cx.llmod, sbuf, val) - } - }) -} - //////////////// pub struct DebugContext { - llmetadata: metadata_cache, + //llmetadata: metadata_cache, names: namegen, - crate_file: ~str + crate_file: ~str, + builder: DIBuilderRef, + + created_files: @mut HashMap<~str, DIFile>, + created_functions: @mut HashMap, + created_blocks: @mut HashMap, + created_types: @mut HashMap } -pub fn mk_ctxt(crate: ~str) -> DebugContext { +/** Create new DebugContext */ +pub fn mk_ctxt(llmod: ModuleRef, crate: ~str, intr: @ident_interner) -> DebugContext { + debug!("mk_ctxt"); + let builder = unsafe { llvm::DIBuilder_new(llmod) }; DebugContext { - llmetadata: @mut HashMap::new(), - names: new_namegen(), - crate_file: crate - } + //llmetadata: @mut HashMap::new(), + names: new_namegen(intr), + crate_file: crate, + builder: builder, + created_files: @mut HashMap::new(), + created_functions: @mut HashMap::new(), + created_blocks: @mut HashMap::new(), + created_types: @mut HashMap::new(), +} } -fn update_cache(cache: metadata_cache, mdtag: int, val: debug_metadata) { - let mut existing = match cache.pop(&mdtag) { - Some(arr) => arr, None => ~[] +#[inline(always)] +fn get_builder(cx: @CrateContext) -> DIBuilderRef { + let dbg_cx = cx.dbg_cx.get_ref(); + return dbg_cx.builder; +} + +fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { + return unsafe { + llvm::DIBuilder_getOrCreateArray(builder, vec::raw::to_ptr(arr), arr.len() as u32) }; - existing.push(val); - cache.insert(mdtag, existing); } -struct Metadata { - node: ValueRef, - data: T -} - -struct FileMetadata { - path: ~str -} -struct CompileUnitMetadata { - name: ~str -} -struct SubProgramMetadata { - id: ast::node_id -} -struct LocalVarMetadata { - id: ast::node_id -} -struct TyDescMetadata { - hash: uint -} -struct BlockMetadata { - start: codemap::Loc, - end: codemap::Loc -} -struct ArgumentMetadata { - id: ast::node_id -} -struct RetvalMetadata { - id: ast::node_id -} - -type metadata_cache = @mut HashMap; - -enum debug_metadata { - file_metadata(@Metadata), - compile_unit_metadata(@Metadata), - subprogram_metadata(@Metadata), - local_var_metadata(@Metadata), - tydesc_metadata(@Metadata), - block_metadata(@Metadata), - argument_metadata(@Metadata), - retval_metadata(@Metadata), -} - -fn cast_safely(val: T) -> U { +/** Create any deferred debug metadata nodes */ +pub fn finalize(cx: @CrateContext) { + debug!("finalize"); + create_compile_unit(cx); unsafe { - let val2 = val; - return cast::transmute(val2); - } + llvm::DIBuilder_finalize(get_builder(cx)); + llvm::DIBuilder_delete(get_builder(cx)); + }; } -fn md_from_metadata(val: debug_metadata) -> T { - match val { - file_metadata(md) => cast_safely(md), - compile_unit_metadata(md) => cast_safely(md), - subprogram_metadata(md) => cast_safely(md), - local_var_metadata(md) => cast_safely(md), - tydesc_metadata(md) => cast_safely(md), - block_metadata(md) => cast_safely(md), - argument_metadata(md) => cast_safely(md), - retval_metadata(md) => cast_safely(md) - } +fn filename_from_span(cx: @CrateContext, sp: codemap::span) -> ~str { + /*bad*/copy cx.sess.codemap.lookup_char_pos(sp.lo).file.name } -fn cached_metadata(cache: metadata_cache, - mdtag: int, - eq_fn: &fn(md: T) -> bool) - -> Option { - if cache.contains_key(&mdtag) { - let items = cache.get(&mdtag); - for items.each |item| { - let md: T = md_from_metadata::(*item); - if eq_fn(copy md) { - return option::Some(copy md); - } - } - } - return option::None; +//fn filename_from_span<'cx>(cx: &'cx CrateContext, sp: codemap::span) -> &'cx str { +// let fname: &str = cx.sess.codemap.lookup_char_pos(sp.lo).file.name; +// return fname; +//} + +fn get_file_path_and_dir(work_dir: &str, full_path: &str) -> (~str, ~str) { + let full_path = + if str::starts_with(full_path, work_dir) { + str::slice(full_path, str::len(work_dir) + 1u, + str::len(full_path)).to_owned() + } else { + full_path.to_owned() + }; + + return (full_path, work_dir.to_owned()); } -fn create_compile_unit(cx: &mut CrateContext) -> @Metadata { - let cache = get_cache(cx); - let crate_name = /*bad*/copy (/*bad*/copy cx.dbg_cx).get().crate_file; - let tg = CompileUnitTag; - match cached_metadata::<@Metadata>(cache, tg, - |md| md.data.name == crate_name) { - option::Some(md) => return md, - option::None => () - } +fn create_compile_unit(cx: @CrateContext) { + let crate_name: &str = cx.dbg_cx.get_ref().crate_file; let (_, work_dir) = get_file_path_and_dir( cx.sess.working_dir.to_str(), crate_name); - let unit_metadata = ~[lltag(tg), - llunused(), - lli32(DW_LANG_RUST), - llstr(crate_name), - llstr(work_dir), - llstr(env!("CFG_VERSION")), - lli1(true), // deprecated: main compile unit - lli1(cx.sess.opts.optimize != session::No), - llstr(""), // flags (???) - lli32(0) // runtime version (???) - ]; - let unit_node = llmdnode(unit_metadata); - add_named_metadata(cx, ~"llvm.dbg.cu", unit_node); - let mdval = @Metadata { - node: unit_node, - data: CompileUnitMetadata { - name: crate_name - } - }; - update_cache(cache, tg, compile_unit_metadata(mdval)); + + let producer = fmt!("rustc version %s", env!("CFG_VERSION")); - return mdval; + do as_c_str(crate_name) |crate_name| { + do as_c_str(work_dir) |work_dir| { + do as_c_str(producer) |producer| { + do as_c_str("") |flags| { + do as_c_str("") |split_name| { unsafe { + llvm::DIBuilder_createCompileUnit(get_builder(cx), + DW_LANG_RUST as c_uint, crate_name, work_dir, producer, + cx.sess.opts.optimize != session::No, + flags, 0, split_name); + }}}}}}; } -fn get_cache(cx: &CrateContext) -> metadata_cache { - cx.dbg_cx.get_ref().llmetadata -} +fn create_file(cx: @CrateContext, full_path: &str) -> DIFile { + let mut dbg_cx = cx.dbg_cx.get_ref(); -fn get_file_path_and_dir(work_dir: &str, full_path: &str) -> (~str, ~str) { - (if full_path.starts_with(work_dir) { - full_path.slice(work_dir.len() + 1u, - full_path.len()).to_owned() - } else { - full_path.to_owned() - }, work_dir.to_owned()) -} - -fn create_file(cx: &mut CrateContext, full_path: ~str) - -> @Metadata { - let cache = get_cache(cx);; - let tg = FileDescriptorTag; - match cached_metadata::<@Metadata>( - cache, tg, |md| md.data.path == full_path) { - option::Some(md) => return md, - option::None => () + match dbg_cx.created_files.find(&full_path.to_owned()) { + Some(file_md) => return *file_md, + None => () } + debug!("create_file: %s", full_path); + let (file_path, work_dir) = get_file_path_and_dir(cx.sess.working_dir.to_str(), full_path); - let unit_node = create_compile_unit(cx).node; - let file_md = ~[lltag(tg), - llstr(file_path), - llstr(work_dir), - unit_node]; - let val = llmdnode(file_md); - let mdval = @Metadata { - node: val, - data: FileMetadata { - path: full_path - } - }; - update_cache(cache, tg, file_metadata(mdval)); - return mdval; + + let file_md = + do as_c_str(file_path) |file_path| { + do as_c_str(work_dir) |work_dir| { unsafe { + llvm::DIBuilder_createFile(get_builder(cx), file_path, work_dir) + }}}; + + dbg_cx.created_files.insert(full_path.to_owned(), file_md); + return file_md; } fn line_from_span(cm: @codemap::CodeMap, sp: span) -> uint { cm.lookup_char_pos(sp.lo).line } -fn create_block(mut cx: block) -> @Metadata { - let cache = get_cache(cx.ccx()); - while cx.node_info.is_none() { - match cx.parent { - Some(b) => cx = b, +fn create_block(bcx: block) -> DILexicalBlock { + let mut bcx = bcx; + let mut dbg_cx = bcx.ccx().dbg_cx.get_ref(); + + while bcx.node_info.is_none() { + match bcx.parent { + Some(b) => bcx = b, None => fail!() } } - let sp = cx.node_info.get().span; + let sp = bcx.node_info.get().span; + let id = bcx.node_info.get().id; - let start = cx.sess().codemap.lookup_char_pos(sp.lo); - let fname = /*bad*/copy start.file.name; - let end = cx.sess().codemap.lookup_char_pos(sp.hi); - let tg = LexicalBlockTag; - /*match cached_metadata::<@Metadata>( - cache, tg, - {|md| start == md.data.start && end == md.data.end}) { - option::Some(md) { return md; } - option::None {} - }*/ - - let parent = match cx.parent { - None => create_function(cx.fcx).node, - Some(bcx) => create_block(bcx).node - }; - let file_node = create_file(cx.ccx(), /* bad */ fname.to_owned()); - let unique_id = match cache.find(&LexicalBlockTag) { - option::Some(v) => v.len() as int, - option::None => 0 - }; - let lldata = ~[lltag(tg), - parent, - lli32(start.line.to_int()), - lli32(start.col.to_int()), - file_node.node, - lli32(unique_id) - ]; - let val = llmdnode(lldata); - let mdval = @Metadata { - node: val, - data: BlockMetadata { - start: start, - end: end - } - }; - //update_cache(cache, tg, block_metadata(mdval)); - return mdval; -} - -fn size_and_align_of(cx: &mut CrateContext, t: ty::t) -> (int, int) { - let llty = type_of::type_of(cx, t); - (machine::llsize_of_real(cx, llty) as int, - machine::llalign_of_pref(cx, llty) as int) -} - -fn create_basic_type(cx: &mut CrateContext, t: ty::t, span: span) - -> @Metadata { - let cache = get_cache(cx); - let tg = BasicTypeDescriptorTag; - match cached_metadata::<@Metadata>( - cache, tg, |md| ty::type_id(t) == md.data.hash) { - option::Some(md) => return md, - option::None => () + match dbg_cx.created_blocks.find(&id) { + Some(block) => return *block, + None => () } + debug!("create_block: %s", bcx.sess().codemap.span_to_str(sp)); + + let start = bcx.sess().codemap.lookup_char_pos(sp.lo); + let end = bcx.sess().codemap.lookup_char_pos(sp.hi); + + let parent = match bcx.parent { + None => create_function(bcx.fcx), + Some(b) => create_block(b) + }; + + let file_md = create_file(bcx.ccx(), start.file.name); + + let block_md = unsafe { + llvm::LLVMDIBuilderCreateLexicalBlock( + dcx.builder, + parent, file_md, + start.line.to_int() as c_uint, start.col.to_int() as c_uint) + }; + + dbg_cx.created_blocks.insert(id, block_md); + + return block_md; +} + +fn size_and_align_of(cx: @CrateContext, t: ty::t) -> (uint, uint) { + let llty = type_of::type_of(cx, t); + (machine::llsize_of_real(cx, llty), + machine::llalign_of_pref(cx, llty)) +} + +fn create_basic_type(cx: @CrateContext, t: ty::t, span: span) -> DIType{ + let mut dbg_cx = cx.dbg_cx.get_ref(); + let ty_id = ty::type_id(t); + match dbg_cx.created_types.find(&ty_id) { + Some(ty_md) => return *ty_md, + None => () + } + + debug!("create_basic_type: %?", ty::get(t)); + let (name, encoding) = match ty::get(t).sty { ty::ty_nil | ty::ty_bot => (~"uint", DW_ATE_unsigned), ty::ty_bool => (~"bool", DW_ATE_boolean), @@ -378,383 +257,255 @@ fn create_basic_type(cx: &mut CrateContext, t: ty::t, span: span) ast::ty_f32 => (~"f32", DW_ATE_float), ast::ty_f64 => (~"f64", DW_ATE_float) }, - _ => cx.sess.bug("debuginfo::create_basic_type - t is invalid type") + _ => cx.sess.bug(~"debuginfo::create_basic_type - t is invalid type") }; - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - let cu_node = create_compile_unit(cx); let (size, align) = size_and_align_of(cx, t); - let lldata = ~[lltag(tg), - cu_node.node, - llstr(name), - file_node.node, - lli32(0), //XXX source line - lli64(size * 8), // size in bits - lli64(align * 8), // alignment in bits - lli64(0), //XXX offset? - lli32(0), //XXX flags? - lli32(encoding)]; - let llnode = llmdnode(lldata); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(t) - } - }; - update_cache(cache, tg, tydesc_metadata(mdval)); - add_named_metadata(cx, ~"llvm.dbg.ty", llnode); - return mdval; + let ty_md = do as_c_str(name) |name| { unsafe { + llvm::LLVMDIBuilderCreateBasicType( + dcx.builder, name, + size * 8 as u64, align * 8 as u64, encoding as c_uint) + }}; + + dbg_cx.created_types.insert(ty_id, ty_md); + return ty_md; } -fn create_pointer_type(cx: &mut CrateContext, t: ty::t, span: span, - pointee: @Metadata) - -> @Metadata { - let tg = PointerTypeTag; - /*let cache = cx.llmetadata; - match cached_metadata::<@Metadata>( - cache, tg, {|md| ty::hash_ty(t) == ty::hash_ty(md.data.hash)}) { - option::Some(md) { return md; } - option::None {} - }*/ +fn create_pointer_type(cx: @CrateContext, t: ty::t, span: span, pointee: DIType) -> DIType { let (size, align) = size_and_align_of(cx, t); - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - //let cu_node = create_compile_unit(cx, fname); let name = ty_to_str(cx.tcx, t); - let llnode = create_derived_type(tg, file_node.node, name, 0, size * 8, - align * 8, 0, pointee.node); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(t) - } - }; - //update_cache(cache, tg, tydesc_metadata(mdval)); - add_named_metadata(cx, ~"llvm.dbg.ty", llnode); - return mdval; + let ptr_md = do as_c_str(name) |name| { unsafe { + llvm::DIBuilder_createPointerType(get_builder(cx), + pointee, size * 8 as u64, align * 8 as u64, name) + }}; + return ptr_md; } -struct StructCtxt { - file: ValueRef, - name: @str, - line: int, - members: ~[ValueRef], - total_size: int, - align: int +struct StructContext { + cx: @CrateContext, + file: DIFile, + name: ~str, + line: uint, + members: ~[DIDerivedType], + total_size: uint, + align: uint } -fn finish_structure(cx: @mut StructCtxt) -> ValueRef { - return create_composite_type(StructureTypeTag, - cx.name, - cx.file, - cx.line, - cx.total_size, - cx.align, - 0, - None, - Some(/*bad*/copy cx.members)); +impl StructContext { + fn create(cx: @CrateContext, file: DIFile, name: ~str, line: uint) -> ~StructContext { + let scx = ~StructContext { + cx: cx, + file: file, + name: name, + line: line, + members: ~[], + total_size: 0, + align: 64 //XXX different alignment per arch? + }; + return scx; + } + + fn add_member(&mut self, name: &str, line: uint, size: uint, align: uint, ty: DIType) { + let mem_t = do as_c_str(name) |name| { unsafe { + llvm::DIBuilder_createMemberType(get_builder(self.cx), + ptr::null(), name, self.file, line as c_uint, + size * 8 as u64, align * 8 as u64, self.total_size as u64, + 0, ty) + }}; + // XXX What about member alignment??? + self.members.push(mem_t); + self.total_size += size * 8; + } + + fn finalize(&self) -> DICompositeType { + let members_md = create_DIArray(get_builder(self.cx), self.members); + + let struct_md = + do as_c_str(self.name) |name| { unsafe { + llvm::LLVMDIBuilderCreateStructType( + dcx.builder, ptr::null(), name, + self.file, self.line as c_uint, + self.total_size as u64, self.align as u64, 0, ptr::null(), + members_md, 0, ptr::null()) + }}; + return struct_md; + } } -fn create_structure(file: @Metadata, name: @str, line: int) - -> @mut StructCtxt { - let cx = @mut StructCtxt { - file: file.node, - name: name, - line: line, - members: ~[], - total_size: 0, - align: 64 //XXX different alignment per arch? - }; - return cx; -} - -fn create_derived_type(type_tag: int, file: ValueRef, name: &str, line: int, - size: int, align: int, offset: int, ty: ValueRef) - -> ValueRef { - let lldata = ~[lltag(type_tag), - file, - llstr(name), - file, - lli32(line), - lli64(size), - lli64(align), - lli64(offset), - lli32(0), - ty]; - return llmdnode(lldata); -} - -fn add_member(cx: @mut StructCtxt, - name: &str, - line: int, - size: int, - align: int, - ty: ValueRef) { - cx.members.push(create_derived_type(MemberTag, cx.file, name, line, - size * 8, align * 8, cx.total_size, - ty)); - cx.total_size += size * 8; -} - -fn create_struct(cx: &mut CrateContext, t: ty::t, fields: ~[ty::field], - span: span) -> @Metadata { +fn create_struct(cx: @CrateContext, t: ty::t, fields: ~[ty::field], span: span) -> DICompositeType { let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - let scx = create_structure(file_node, (ty_to_str(cx.tcx, t)).to_managed(), - line_from_span(cx.sess.codemap, span) as int); + let file_md = create_file(cx, fname); + let line = line_from_span(cx.sess.codemap, span); + + let mut scx = StructContext::create(cx, file_md, ty_to_str(cx.tcx, t), line); for fields.each |field| { let field_t = field.mt.ty; let ty_md = create_ty(cx, field_t, span); let (size, align) = size_and_align_of(cx, field_t); - add_member(scx, cx.sess.str_of(field.ident), - line_from_span(cx.sess.codemap, span) as int, - size as int, align as int, ty_md.node); + scx.add_member(cx.sess.str_of(field.ident), + line_from_span(cx.sess.codemap, span), + size, align, ty_md); } - let mdval = @Metadata { - node: finish_structure(scx), - data: TyDescMetadata { - hash: ty::type_id(t) - } - }; - return mdval; -} - -fn create_tuple(cx: &mut CrateContext, t: ty::t, elements: &[ty::t], span: span) - -> @Metadata { - let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - let scx = create_structure(file_node, - cx.sess.str_of( - ((/*bad*/copy cx.dbg_cx).get().names) - ("tuple")), - line_from_span(cx.sess.codemap, span) as int); - for elements.each |element| { - let ty_md = create_ty(cx, *element, span); - let (size, align) = size_and_align_of(cx, *element); - add_member(scx, "", line_from_span(cx.sess.codemap, span) as int, - size as int, align as int, ty_md.node); - } - let mdval = @Metadata { - node: finish_structure(scx), - data: TyDescMetadata { - hash: ty::type_id(t) - } - }; - return mdval; + return scx.finalize(); } // returns (void* type as a ValueRef, size in bytes, align in bytes) -fn voidptr() -> (ValueRef, int, int) { - let null = ptr::null(); - let size = sys::size_of::() as int; - let align = sys::min_align_of::() as int; - let vp = create_derived_type(PointerTypeTag, null, "", 0, +fn voidptr() -> (DIDerivedType, uint, uint) { + let size = sys::size_of::(); + let align = sys::min_align_of::(); + let vp = ptr::null(); + /* + let vp = create_derived_type(PointerTypeTag, null, ~"", 0, size, align, 0, null); + */ return (vp, size, align); } -fn create_boxed_type(cx: &mut CrateContext, contents: ty::t, - span: span, boxed: @Metadata) - -> @Metadata { - //let tg = StructureTypeTag; - /*let cache = cx.llmetadata; - match cached_metadata::<@Metadata>( - cache, tg, {|md| ty::hash_ty(contents) == ty::hash_ty(md.data.hash)}) { - option::Some(md) { return md; } - option::None {} - }*/ +fn create_tuple(cx: @CrateContext, t: ty::t, elements: &[ty::t], span: span) -> DICompositeType { let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); - //let cu_node = create_compile_unit_metadata(cx, fname); + let file_md = create_file(cx, fname); + + let name = (cx.sess.str_of((dcx.names)("tuple"))).to_owned(); + let mut scx = StructContext::create(cx, file_md, name, loc.line); + + for elements.each |element| { + let ty_md = create_ty(cx, *element, span); + let (size, align) = size_and_align_of(cx, *element); + scx.add_member("", line_from_span(cx.sess.codemap, span), + size, align, ty_md); + } + return scx.finalize(); +} + +fn create_boxed_type(cx: @CrateContext, contents: ty::t, + span: span, boxed: DIType) -> DICompositeType { + let fname = filename_from_span(cx, span); + let file_md = create_file(cx, fname); let int_t = ty::mk_int(); let refcount_type = create_basic_type(cx, int_t, span); let name = ty_to_str(cx.tcx, contents); - let scx = create_structure(file_node, (fmt!("box<%s>", name)).to_managed(), 0); - add_member(scx, "refcnt", 0, sys::size_of::() as int, - sys::min_align_of::() as int, refcount_type.node); + + let mut scx = StructContext::create(cx, file_md, fmt!("box<%s>", name), 0); + scx.add_member("refcnt", 0, sys::size_of::(), + sys::min_align_of::(), refcount_type); // the tydesc and other pointers should be irrelevant to the // debugger, so treat them as void* types let (vp, vpsize, vpalign) = voidptr(); - add_member(scx, "tydesc", 0, vpsize, vpalign, vp); - add_member(scx, "prev", 0, vpsize, vpalign, vp); - add_member(scx, "next", 0, vpsize, vpalign, vp); + scx.add_member("tydesc", 0, vpsize, vpalign, vp); + scx.add_member("prev", 0, vpsize, vpalign, vp); + scx.add_member("next", 0, vpsize, vpalign, vp); let (size, align) = size_and_align_of(cx, contents); - add_member(scx, "boxed", 0, size, align, boxed.node); - let llnode = finish_structure(scx); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(contents) - } - }; - //update_cache(cache, tg, tydesc_metadata(mdval)); - add_named_metadata(cx, ~"llvm.dbg.ty", llnode); - return mdval; + scx.add_member("boxed", 0, size, align, boxed); + return scx.finalize(); } -fn create_composite_type(type_tag: int, name: &str, file: ValueRef, - line: int, size: int, align: int, offset: int, - derived: Option, - members: Option<~[ValueRef]>) - -> ValueRef { - let lldata = ~[lltag(type_tag), - file, - llstr(name), // type name - file, // source file definition - lli32(line), // source line definition - lli64(size), // size of members - lli64(align), // align - lli32/*64*/(offset), // offset - lli32(0), // flags - if derived.is_none() { - llnull() - } else { // derived from - derived.get() - }, - if members.is_none() { - llnull() - } else { //members - llmdnode(members.get()) - }, - lli32(0), // runtime language - llnull() - ]; - return llmdnode(lldata); -} - -fn create_fixed_vec(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, - len: int, span: span) -> @Metadata { - let t_md = create_ty(cx, elem_t, span); +fn create_fixed_vec(cx: @CrateContext, vec_t: ty::t, elem_t: ty::t, + len: uint, span: span) -> DIType { + let elem_ty_md = create_ty(cx, elem_t, span); let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); + let file_md = create_file(cx, fname); let (size, align) = size_and_align_of(cx, elem_t); - let subrange = llmdnode([lltag(SubrangeTag), lli64(0), lli64(len - 1)]); - let name = fmt!("[%s]", ty_to_str(cx.tcx, elem_t)); - let array = create_composite_type(ArrayTypeTag, name, file_node.node, 0, - size * len, align, 0, Some(t_md.node), - Some(~[subrange])); - @Metadata { - node: array, - data: TyDescMetadata { - hash: ty::type_id(vec_t) - } - } + + let subrange = unsafe { + llvm::DIBuilder_getOrCreateSubrange(get_builder(cx), 0_i64, (len-1) as i64) }; + + let subscripts = create_DIArray(get_builder(cx), [subrange]); + return unsafe { + llvm::DIBuilder_createVectorType(get_builder(cx), + size * len as u64, align as u64, elem_ty_md, subscripts) + }; } -fn create_boxed_vec(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, - vec_ty_span: codemap::span) - -> @Metadata { +fn create_boxed_vec(cx: @CrateContext, vec_t: ty::t, elem_t: ty::t, + vec_ty_span: codemap::span) -> DICompositeType { let fname = filename_from_span(cx, vec_ty_span); - let file_node = create_file(cx, fname.to_owned()); + let file_md = create_file(cx, fname); let elem_ty_md = create_ty(cx, elem_t, vec_ty_span); - let vec_scx = create_structure(file_node, - ty_to_str(cx.tcx, vec_t).to_managed(), 0); + + let mut vec_scx = StructContext::create(cx, file_md, ty_to_str(cx.tcx, vec_t), 0); + let size_t_type = create_basic_type(cx, ty::mk_uint(), vec_ty_span); - add_member(vec_scx, "fill", 0, sys::size_of::() as int, - sys::min_align_of::() as int, size_t_type.node); - add_member(vec_scx, "alloc", 0, sys::size_of::() as int, - sys::min_align_of::() as int, size_t_type.node); - let subrange = llmdnode([lltag(SubrangeTag), lli64(0), lli64(0)]); + vec_scx.add_member("fill", 0, sys::size_of::(), + sys::min_align_of::(), size_t_type); + vec_scx.add_member("alloc", 0, sys::size_of::(), + sys::min_align_of::(), size_t_type); + let subrange = unsafe { llvm::DIBuilder_getOrCreateSubrange(get_builder(cx), 0_i64, 0_i64) }; let (arr_size, arr_align) = size_and_align_of(cx, elem_t); let name = fmt!("[%s]", ty_to_str(cx.tcx, elem_t)); - let data_ptr = create_composite_type(ArrayTypeTag, name, file_node.node, 0, - arr_size, arr_align, 0, - Some(elem_ty_md.node), - Some(~[subrange])); - add_member(vec_scx, "data", 0, 0, // clang says the size should be 0 - sys::min_align_of::() as int, data_ptr); - let llnode = finish_structure(vec_scx); - let vec_md = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(vec_t) - } - }; - let box_scx = create_structure(file_node, (fmt!("box<%s>", name)).to_managed(), 0); + let subscripts = create_DIArray(get_builder(cx), [subrange]); + let data_ptr = unsafe { llvm::DIBuilder_createVectorType(get_builder(cx), + arr_size as u64, arr_align as u64, elem_ty_md, subscripts) }; + vec_scx.add_member("data", 0, 0, // clang says the size should be 0 + sys::min_align_of::(), data_ptr); + let vec_md = vec_scx.finalize(); + + let mut box_scx = StructContext::create(cx, file_md, fmt!("box<%s>", name), 0); let int_t = ty::mk_int(); let refcount_type = create_basic_type(cx, int_t, vec_ty_span); - add_member(box_scx, "refcnt", 0, sys::size_of::() as int, - sys::min_align_of::() as int, refcount_type.node); + box_scx.add_member("refcnt", 0, sys::size_of::(), + sys::min_align_of::(), refcount_type); let (vp, vpsize, vpalign) = voidptr(); - add_member(box_scx, "tydesc", 0, vpsize, vpalign, vp); - add_member(box_scx, "prev", 0, vpsize, vpalign, vp); - add_member(box_scx, "next", 0, vpsize, vpalign, vp); - let size = 2 * sys::size_of::() as int; - let align = sys::min_align_of::() as int; - add_member(box_scx, "boxed", 0, size, align, vec_md.node); - let llnode = finish_structure(box_scx); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(elem_t) - } - }; + box_scx.add_member("tydesc", 0, vpsize, vpalign, vp); + box_scx.add_member("prev", 0, vpsize, vpalign, vp); + box_scx.add_member("next", 0, vpsize, vpalign, vp); + let size = 2 * sys::size_of::(); + let align = sys::min_align_of::(); + box_scx.add_member("boxed", 0, size, align, vec_md); + let mdval = box_scx.finalize(); return mdval; } -fn create_vec_slice(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: span) - -> @Metadata { +fn create_vec_slice(cx: @CrateContext, vec_t: ty::t, elem_t: ty::t, span: span) -> DICompositeType { let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); + let file_md = create_file(cx, fname); let elem_ty_md = create_ty(cx, elem_t, span); let uint_type = create_basic_type(cx, ty::mk_uint(), span); let elem_ptr = create_pointer_type(cx, elem_t, span, elem_ty_md); - let scx = create_structure(file_node, ty_to_str(cx.tcx, vec_t).to_managed(), 0); + + let mut scx = StructContext::create(cx, file_md, ty_to_str(cx.tcx, vec_t), 0); let (_, ptr_size, ptr_align) = voidptr(); - add_member(scx, "vec", 0, ptr_size, ptr_align, elem_ptr.node); - add_member(scx, "length", 0, sys::size_of::() as int, - sys::min_align_of::() as int, uint_type.node); - let llnode = finish_structure(scx); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(vec_t) - } - }; - return mdval; + scx.add_member("vec", 0, ptr_size, ptr_align, elem_ptr); + scx.add_member("length", 0, sys::size_of::(), + sys::min_align_of::(), uint_type); + return scx.finalize(); } -fn create_fn_ty(cx: &mut CrateContext, fn_ty: ty::t, inputs: ~[ty::t], output: ty::t, - span: span) -> @Metadata { +fn create_fn_ty(cx: @CrateContext, fn_ty: ty::t, inputs: ~[ty::t], output: ty::t, + span: span) -> DICompositeType { let fname = filename_from_span(cx, span); - let file_node = create_file(cx, fname.to_owned()); + let file_md = create_file(cx, fname); let (vp, _, _) = voidptr(); let output_md = create_ty(cx, output, span); let output_ptr_md = create_pointer_type(cx, output, span, output_md); - let inputs_vals = do inputs.map |arg| { create_ty(cx, *arg, span).node }; - let members = ~[output_ptr_md.node, vp] + inputs_vals; - let llnode = create_composite_type(SubroutineTag, "", file_node.node, - 0, 0, 0, 0, None, Some(members)); - let mdval = @Metadata { - node: llnode, - data: TyDescMetadata { - hash: ty::type_id(fn_ty) - } + let inputs_vals = do inputs.map |arg| { create_ty(cx, *arg, span) }; + let members = ~[output_ptr_md, vp] + inputs_vals; + + return unsafe { + llvm::DIBuilder_createSubroutineType(get_builder(cx), file_md, + create_DIArray(get_builder(cx), members)) }; - return mdval; } -fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) - -> @Metadata { +fn create_ty(cx: @CrateContext, t: ty::t, span: span) -> DIType { + let mut dbg_cx = cx.dbg_cx.get_ref(); + let ty_id = ty::type_id(t); + match dbg_cx.created_types.find(&ty_id) { + Some(ty_md) => return *ty_md, + None => () + } + debug!("create_ty: %?", ty::get(t)); - /*let cache = get_cache(cx); - match cached_metadata::<@Metadata>( - cache, tg, {|md| t == md.data.hash}) { - option::Some(md) { return md; } - option::None {} - }*/ let sty = copy ty::get(t).sty; - match sty { + let ty_md = match sty { ty::ty_nil | ty::ty_bot | ty::ty_bool | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) => create_basic_type(cx, t, span), ty::ty_estr(ref vstore) => { let i8_t = ty::mk_i8(); match *vstore { ty::vstore_fixed(len) => { - create_fixed_vec(cx, t, i8_t, len as int + 1, span) + create_fixed_vec(cx, t, i8_t, len + 1, span) }, ty::vstore_uniq | ty::vstore_box => { let box_md = create_boxed_vec(cx, t, i8_t, span); @@ -776,7 +527,7 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) ty::ty_evec(ref mt, ref vstore) => { match *vstore { ty::vstore_fixed(len) => { - create_fixed_vec(cx, t, mt.ty, len as int, span) + create_fixed_vec(cx, t, mt.ty, len, span) }, ty::vstore_uniq | ty::vstore_box => { let box_md = create_boxed_vec(cx, t, mt.ty, span); @@ -812,30 +563,17 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span) ty::ty_tup(ref elements) => { create_tuple(cx, t, *elements, span) }, - _ => cx.sess.bug("debuginfo: unexpected type in create_ty") - } + _ => cx.sess.bug(~"debuginfo: unexpected type in create_ty") + }; + + dbg_cx.created_types.insert(ty_id, ty_md); + return ty_md; } -fn filename_from_span(cx: &CrateContext, sp: codemap::span) -> @str { - cx.sess.codemap.lookup_char_pos(sp.lo).file.name -} - -fn create_var(type_tag: int, context: ValueRef, name: &str, file: ValueRef, - line: int, ret_ty: ValueRef) -> ValueRef { - let lldata = ~[lltag(type_tag), - context, - llstr(name), - file, - lli32(line), - ret_ty, - lli32(0) - ]; - return llmdnode(lldata); -} - -pub fn create_local_var(bcx: block, local: @ast::local) - -> @Metadata { +pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable { + debug!("create_local_var"); let cx = bcx.ccx(); + /* let cache = get_cache(cx); let tg = AutoVariableTag; match cached_metadata::<@Metadata>( @@ -843,49 +581,56 @@ pub fn create_local_var(bcx: block, local: @ast::local) option::Some(md) => return md, option::None => () } + */ let name = match local.node.pat.node { ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth), // FIXME this should be handled (#2533) _ => fail!("no single variable name for local") }; - let loc = cx.sess.codemap.lookup_char_pos(local.span.lo); + let name: &str = cx.sess.str_of(ident); + debug!("create_local_var: %s", name); + + let loc = span_start(cx, local.span); let ty = node_id_type(bcx, local.node.id); let tymd = create_ty(cx, ty, local.node.ty.span); - let filemd = create_file(cx, /*bad*/ loc.file.name.to_owned()); + let filemd = create_file(cx, /*bad*/copy loc.file.name); let context = match bcx.parent { - None => create_function(bcx.fcx).node, - Some(_) => create_block(bcx).node + None => create_function(bcx.fcx), + Some(_) => create_block(bcx) }; - let mdnode = create_var(tg, context, cx.sess.str_of(name), - filemd.node, loc.line as int, tymd.node); - let mdval = @Metadata { - node: mdnode, - data: LocalVarMetadata { - id: local.node.id - } - }; - update_cache(cache, AutoVariableTag, local_var_metadata(mdval)); - // FIXME(#6814) Should use `pat_util::pat_bindings` for pats like (a, b) etc - let llptr = match bcx.fcx.lllocals.find_copy(&local.node.pat.id) { - Some(v) => v, - None => { - bcx.tcx().sess.span_bug( - local.span, - fmt!("No entry in lllocals table for %?", local.node.id)); + let mdval = do as_c_str(*cx.sess.str_of(name)) |name| { unsafe { + llvm::DIBuilder_createLocalVariable(get_builder(cx), AutoVariableTag as u32, + ptr::null(), name, filemd, loc.line as c_uint, tymd, false, 0, 0) + }}; + + let llptr = match bcx.fcx.lllocals.find(&local.node.id) { + option::Some(&local_mem(v)) => v, + option::Some(_) => { + bcx.tcx().sess.span_bug(local.span, "local is bound to something weird"); } + option::None => { + match bcx.fcx.lllocals.get_copy(&local.node.pat.id) { + local_imm(v) => v, + _ => bcx.tcx().sess.span_bug(local.span, "local is bound to something weird") + } + } }; - let declargs = ~[llmdnode([llptr]), mdnode]; - trans::build::Call(bcx, cx.intrinsics.get_copy(&("llvm.dbg.declare")), + /* + llvm::DIBuilder_insertDeclare(get_builder(cx), llptr, mdval, + + let declargs = ~[llmdnode(~[llptr]), mdnode]; + trans::build::Call(bcx, *cx.intrinsics.get(&~"llvm.dbg.declare"), declargs); + */ return mdval; -} + } -pub fn create_arg(bcx: block, arg: ast::arg, sp: span) - -> Option<@Metadata> { - let fcx = bcx.fcx; - let cx = fcx.ccx; +pub fn create_arg(bcx: block, arg: ast::arg, sp: span) -> Option { + debug!("create_arg"); + let fcx = bcx.fcx, cx = *fcx.ccx; + /* let cache = get_cache(cx); let tg = ArgVariableTag; match cached_metadata::<@Metadata>( @@ -893,6 +638,7 @@ pub fn create_arg(bcx: block, arg: ast::arg, sp: span) option::Some(md) => return Some(md), option::None => () } + */ let loc = cx.sess.codemap.lookup_char_pos(sp.lo); if "" == loc.file.name { @@ -900,35 +646,30 @@ pub fn create_arg(bcx: block, arg: ast::arg, sp: span) } let ty = node_id_type(bcx, arg.id); let tymd = create_ty(cx, ty, arg.ty.span); - let filemd = create_file(cx, /* bad */ loc.file.name.to_owned()); + let filemd = create_file(cx, /*bad*/copy loc.file.name); let context = create_function(bcx.fcx); match arg.pat.node { ast::pat_ident(_, path, _) => { // XXX: This is wrong; it should work for multiple bindings. - let mdnode = create_var( - tg, - context.node, - cx.sess.str_of(*path.idents.last()), - filemd.node, - loc.line as int, - tymd.node - ); + let ident = path.idents.last(); + let name: &str = cx.sess.str_of(*ident); + let mdnode = do as_c_str(name) |name| { unsafe { + llvm::LLVMDIBuilderCreateLocalVariable(dcx.builder, + ArgVariableTag as u32, context, name, + filemd, loc.line as c_uint, tymd, false, 0, 0) + // XXX need to pass a real argument number + }}; - let mdval = @Metadata { - node: mdnode, - data: ArgumentMetadata { - id: arg.id - } + let llptr = match fcx.llargs.get_copy(&arg.id) { + local_mem(v) | local_imm(v) => v, }; - update_cache(cache, tg, argument_metadata(mdval)); - - let llptr = fcx.llargs.get_copy(&arg.id); - let declargs = ~[llmdnode([llptr]), mdnode]; - trans::build::Call(bcx, - cx.intrinsics.get_copy(&("llvm.dbg.declare")), - declargs); - return Some(mdval); + + /* + llvm::DIBuilder_insertDeclare(get_builder(cx), mdnode, llptr, mdnode + */ + + return Some(mdnode); } _ => { return None; @@ -936,32 +677,27 @@ pub fn create_arg(bcx: block, arg: ast::arg, sp: span) } } -pub fn update_source_pos(cx: block, s: span) { - if !cx.sess().opts.debuginfo || (*s.lo == 0 && *s.hi == 0) { - return; - } - let cm = cx.sess().codemap; - let blockmd = create_block(cx); - let loc = cm.lookup_char_pos(s.lo); - let scopedata = ~[lli32(loc.line.to_int()), - lli32(loc.col.to_int()), - blockmd.node, - llnull()]; - let dbgscope = llmdnode(scopedata); +fn create_debug_loc(line: int, col: int, scope: DIScope) -> DILocation { + let elems = ~[C_i32(line as i32), C_i32(col as i32), scope, ptr::null()]; unsafe { - llvm::LLVMSetCurrentDebugLocation(trans::build::B(cx), dbgscope); + return llvm::LLVMMDNode(vec::raw::to_ptr(elems), elems.len() as libc::c_uint); } } -pub fn create_function(fcx: fn_ctxt) -> @Metadata { - let mut cx = fcx.ccx; - - debug!("~~"); + let cm = bcx.sess().codemap; + let blockmd = create_block(bcx); + let loc = cm.lookup_char_pos(sp.lo); + let dbgscope = create_debug_loc(loc.line.to_int(), loc.col.to_int(), blockmd); + unsafe { + llvm::LLVMSetCurrentDebugLocation(trans::build::B(bcx), dbgscope); + } +} +pub fn create_function(fcx: fn_ctxt) -> DISubprogram { + let cx = *fcx.ccx; + let mut dbg_cx = cx.dbg_cx.get_ref(); let fcx = &mut *fcx; - let sp = fcx.span.get(); - debug!("%s", cx.sess.codemap.span_to_str(sp)); let (ident, ret_ty, id) = match cx.tcx.items.get_copy(&fcx.id) { ast_map::node_item(item, _) => { @@ -978,7 +714,6 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata { ast_map::node_expr(expr) => { match expr.node { ast::expr_fn_block(ref decl, _) => { - let dbg_cx = cx.dbg_cx.get_ref(); ((dbg_cx.names)("fn"), decl.output, expr.id) } _ => fcx.ccx.sess.span_bug(expr.span, @@ -988,62 +723,46 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata { _ => fcx.ccx.sess.bug("create_function: unexpected sort of node") }; - debug!("%?", ident); - debug!("%?", id); - - let cache = get_cache(cx); - match cached_metadata::<@Metadata>( - cache, SubprogramTag, |md| md.data.id == id) { - option::Some(md) => return md, - option::None => () + match dbg_cx.created_functions.find(&id) { + Some(fn_md) => return *fn_md, + None => () } + debug!("create_function: %s, %s", cx.sess.str_of(ident), cx.sess.codemap.span_to_str(span)); + let loc = cx.sess.codemap.lookup_char_pos(sp.lo); - let file_node = create_file(cx, loc.file.name.to_owned()).node; - let ty_node = if cx.sess.opts.extra_debuginfo { + let file_md = create_file(cx, loc.file.name); + + let ret_ty_md = if cx.sess.opts.extra_debuginfo { match ret_ty.node { - ast::ty_nil => llnull(), + ast::ty_nil => ptr::null(), _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id), - ret_ty.span).node + ret_ty.span) } } else { - llnull() + ptr::null() }; - let sub_node = create_composite_type(SubroutineTag, "", file_node, 0, 0, - 0, 0, option::None, - option::Some(~[ty_node])); - let fn_metadata = ~[lltag(SubprogramTag), - llunused(), - file_node, - llstr(cx.sess.str_of(ident)), - //XXX fully-qualified C++ name: - llstr(cx.sess.str_of(ident)), - llstr(""), //XXX MIPS name????? - file_node, - lli32(loc.line as int), - sub_node, - lli1(false), //XXX static (check export) - lli1(true), // defined in compilation unit - lli32(DW_VIRTUALITY_none), // virtual-ness - lli32(0i), //index into virt func - /*llnull()*/ lli32(0), // base type with vtbl - lli32(256), // flags - lli1(cx.sess.opts.optimize != session::No), - fcx.llfn - //list of template params - //func decl descriptor - //list of func vars - ]; - let val = llmdnode(fn_metadata); - add_named_metadata(cx, ~"llvm.dbg.sp", val); - let mdval = @Metadata { - node: val, - data: SubProgramMetadata { - id: id - } - }; - update_cache(cache, SubprogramTag, subprogram_metadata(mdval)); + let fn_ty = unsafe { + llvm::DIBuilder_createSubroutineType(get_builder(cx), + file_md, create_DIArray(get_builder(cx), [ret_ty_md])) + }; - return mdval; + let fn_md = + do as_c_str(cx.sess.str_of(ident)) |name| { + do as_c_str(cx.sess.str_of(ident)) |linkage| { unsafe { + llvm::LLVMDIBuilderCreateFunction( + dcx.builder, + file_md, + name, linkage, + file_md, loc.line as c_uint, + fn_ty, false, true, + loc.line as c_uint, + FlagPrototyped as c_uint, + cx.sess.opts.optimize != session::No, + fcx.llfn, ptr::null(), ptr::null()) + }}}; + + dbg_cx.created_functions.insert(id, fn_md); + return fn_md; } diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index ba87624e2dde..315e7c4bcb12 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -560,3 +560,204 @@ extern "C" bool LLVMRustStartMultithreading() { assert(lock.release()); return ret; } + + +typedef DIBuilder* DIBuilderRef; + +template +DIT unwrapDI(LLVMValueRef ref) { return DIT(ref ? unwrap(ref) : NULL); } + +extern "C" DIBuilderRef DIBuilder_new(LLVMModuleRef M) { + return new DIBuilder(*unwrap(M)); +} + +extern "C" void DIBuilder_delete(DIBuilderRef Builder) { + delete Builder; +} + +extern "C" void DIBuilder_finalize(DIBuilderRef Builder) { + Builder->finalize(); +} + +extern "C" void DIBuilder_createCompileUnit( + DIBuilderRef Builder, + unsigned Lang, + const char* File, + const char* Dir, + const char* Producer, + bool isOptimized, + const char* Flags, + unsigned RuntimeVer, + const char* SplitName) { + Builder->createCompileUnit(Lang, File, Dir, Producer, isOptimized, + Flags, RuntimeVer, SplitName); +} + +extern "C" LLVMValueRef DIBuilder_createFile( + DIBuilderRef Builder, + const char* Filename, + const char* Directory) { + return wrap(Builder->createFile(Filename, Directory)); +} + +extern "C" LLVMValueRef DIBuilder_createSubroutineType( + DIBuilderRef Builder, + LLVMValueRef File, + LLVMValueRef ParameterTypes) { + return wrap(Builder->createSubroutineType( + unwrapDI(File), + unwrapDI(ParameterTypes))); +} + +extern "C" LLVMValueRef DIBuilder_createFunction( + DIBuilderRef Builder, + LLVMValueRef Scope, + const char* Name, + const char* LinkageName, + LLVMValueRef File, + unsigned LineNo, + LLVMValueRef Ty, + bool isLocalToUnit, + bool isDefinition, + unsigned ScopeLine, + unsigned Flags, + bool isOptimized, + LLVMValueRef Fn, + LLVMValueRef TParam, + LLVMValueRef Decl) { + return wrap(Builder->createFunction( + unwrapDI(Scope), Name, LinkageName, + unwrapDI(File), LineNo, + unwrapDI(Ty), isLocalToUnit, isDefinition, ScopeLine, + Flags, isOptimized, + unwrap(Fn), + unwrapDI(TParam), + unwrapDI(Decl))); +} + +extern "C" LLVMValueRef DIBuilder_createBasicType( + DIBuilderRef Builder, + const char* Name, + uint64_t SizeInBits, + uint64_t AlignInBits, + unsigned Encoding) { + return wrap(Builder->createBasicType( + Name, SizeInBits, + AlignInBits, Encoding)); +} + +extern "C" LLVMValueRef DIBuilder_createPointerType( + DIBuilderRef Builder, + LLVMValueRef PointeeTy, + uint64_t SizeInBits, + uint64_t AlignInBits, + const char* Name) { + return wrap(Builder->createPointerType( + unwrapDI(PointeeTy), SizeInBits, AlignInBits, Name)); +} + +extern "C" LLVMValueRef DIBuilder_createStructType( + DIBuilderRef Builder, + LLVMValueRef Scope, + const char* Name, + LLVMValueRef File, + unsigned LineNumber, + uint64_t SizeInBits, + uint64_t AlignInBits, + unsigned Flags, + LLVMValueRef DerivedFrom, + LLVMValueRef Elements, + unsigned RunTimeLang, + LLVMValueRef VTableHolder) { + return wrap(Builder->createStructType( + unwrapDI(Scope), Name, + unwrapDI(File), LineNumber, + SizeInBits, AlignInBits, Flags, + unwrapDI(DerivedFrom), + unwrapDI(Elements), RunTimeLang, + unwrapDI(VTableHolder))); +} + +extern "C" LLVMValueRef DIBuilder_createMemberType( + DIBuilderRef Builder, + LLVMValueRef Scope, + const char* Name, + LLVMValueRef File, + unsigned LineNo, + uint64_t SizeInBits, + uint64_t AlignInBits, + uint64_t OffsetInBits, + unsigned Flags, + LLVMValueRef Ty) { + return wrap(Builder->createMemberType( + unwrapDI(Scope), Name, + unwrapDI(File), LineNo, + SizeInBits, AlignInBits, OffsetInBits, Flags, + unwrapDI(Ty))); +} + +extern "C" LLVMValueRef DIBuilder_createLexicalBlock( + DIBuilderRef Builder, + LLVMValueRef Scope, + LLVMValueRef File, + unsigned Line, + unsigned Col) { + return wrap(Builder->createLexicalBlock( + unwrapDI(Scope), + unwrapDI(File), Line, Col)); +} + +extern "C" LLVMValueRef DIBuilder_createLocalVariable( + DIBuilderRef Builder, + unsigned Tag, + LLVMValueRef Scope, + const char* Name, + LLVMValueRef File, + unsigned LineNo, + LLVMValueRef Ty, + bool AlwaysPreserve, + unsigned Flags, + unsigned ArgNo) { + return wrap(Builder->createLocalVariable(Tag, + unwrapDI(Scope), Name, + unwrapDI(File), + LineNo, + unwrapDI(Ty), AlwaysPreserve, Flags, ArgNo)); +} + +extern "C" LLVMValueRef DIBuilder_createVectorType( + DIBuilderRef Builder, + uint64_t Size, + uint64_t AlignInBits, + LLVMValueRef Ty, + LLVMValueRef Subscripts) { + return wrap(Builder->createVectorType(Size, AlignInBits, + unwrapDI(Ty), + unwrapDI(Subscripts))); +} + +extern "C" LLVMValueRef DIBuilder_getOrCreateSubrange( + DIBuilderRef Builder, + int64_t Lo, + int64_t Count) { + return wrap(Builder->getOrCreateSubrange(Lo, Count)); +} + +extern "C" LLVMValueRef DIBuilder_getOrCreateArray( + DIBuilderRef Builder, + LLVMValueRef* Ptr, + unsigned Count) { + return wrap(Builder->getOrCreateArray( + ArrayRef(reinterpret_cast(Ptr), Count))); +} + +extern "C" LLVMValueRef DIBuilder_insertDeclare( + DIBuilderRef Builder, + LLVMValueRef Val, + LLVMValueRef VarInfo, + LLVMValueRef InsertBefore) { + return wrap(Builder->insertDeclare( + unwrap(Val), + unwrapDI(VarInfo), + unwrap(InsertBefore))); +} diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index f53971657819..71d574aecbec 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -588,3 +588,20 @@ LLVMInlineAsm LLVMInitializePasses LLVMAddPass LLVMCreatePass +DIBuilder_new +DIBuilder_delete +DIBuilder_finalize +DIBuilder_createCompileUnit +DIBuilder_createLocalVariable +DIBuilder_createFunction +DIBuilder_createFile +DIBuilder_createLexicalBlock +DIBuilder_createBasicType +DIBuilder_createPointerType +DIBuilder_createMemberType +DIBuilder_createStructType +DIBuilder_getOrCreateSubrange +DIBuilder_createVectorType +DIBuilder_createSubroutineType +DIBuilder_getOrCreateArray +DIBuilder_insertDeclare diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h index 6f11202800cd..d4202abd2854 100644 --- a/src/rustllvm/rustllvm.h +++ b/src/rustllvm/rustllvm.h @@ -43,6 +43,8 @@ #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Vectorize.h" +#include "llvm/DebugInfo.h" +#include "llvm/DIBuilder.h" #include "llvm-c/Core.h" #include "llvm-c/BitReader.h" #include "llvm-c/ExecutionEngine.h"