about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-06-17 14:01:35 -0700
committerbors <bors@rust-lang.org>2013-06-17 14:01:35 -0700
commit4bf074cc66974143178a6add3a7c2e2196ea5a32 (patch)
tree0b57c19fce94133f8eee96f7367bfedb86f7a812
parent644774c1b15c107d8cb74c756ea69e342844a5c9 (diff)
parentadff46250ed9e9b3c31da65b2997a5458e41305a (diff)
downloadrust-4bf074cc66974143178a6add3a7c2e2196ea5a32.tar.gz
rust-4bf074cc66974143178a6add3a7c2e2196ea5a32.zip
auto merge of #7134 : vadimcn/rust/DIBuilder, r=jdm
This commit fixes rustc's debug info generation and turns debug-info tests back on.

The old generator used to write out LLVM metadata directly, however it seems that debug metadata format is not stable and keeps changing from release to release.  So I wrapped LLVM's official debug info API - the DIBuilder class, and now rustc will use that.

One bit of old functionality that still doesn't work, is debug info for function arguments.  Someone more familiar with the compiler guts will need to look into that.

Also, unfortunately, debug info is still won't work on Windows,- due to a LLVM bug (http://llvm.org/bugs/show_bug.cgi?id=16249).

Resolves issues #5836, #5848, #6814

-rw-r--r--src/compiletest/procsrv.rs2
-rw-r--r--src/librustc/lib/llvm.rs205
-rw-r--r--src/librustc/middle/trans/base.rs9
-rw-r--r--src/librustc/middle/trans/context.rs2
-rw-r--r--src/librustc/middle/trans/debuginfo.rs1185
-rw-r--r--src/rustllvm/RustWrapper.cpp225
-rw-r--r--src/rustllvm/rustllvm.def.in19
-rw-r--r--src/rustllvm/rustllvm.h2
-rw-r--r--src/test/debug-info/basic-types.rs9
-rw-r--r--src/test/debug-info/box.rs9
-rw-r--r--src/test/debug-info/struct.rs9
-rw-r--r--src/test/debug-info/tuple.rs9
-rw-r--r--src/test/debug-info/vec.rs9
13 files changed, 946 insertions, 748 deletions
diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs
index b5404e38ec9..93fe258d167 100644
--- a/src/compiletest/procsrv.rs
+++ b/src/compiletest/procsrv.rs
@@ -23,7 +23,7 @@ fn target_env(lib_path: &str, prog: &str) -> ~[(~str,~str)] {
     assert!(prog.ends_with(".exe"));
     let aux_path = prog.slice(0u, prog.len() - 4u).to_owned() + ".libaux";
 
-    env = do vec::map(env) |pair| {
+    env = do env.map() |pair| {
         let (k,v) = copy *pair;
         if k == ~"PATH" { (~"PATH", v + ";" + lib_path + ";" + aux_path) }
         else { (k,v) }
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs
index 289bb4f63f5..835dd55711b 100644
--- a/src/librustc/lib/llvm.rs
+++ b/src/librustc/lib/llvm.rs
@@ -224,13 +224,50 @@ pub type SectionIteratorRef = *SectionIterator_opaque;
 pub enum Pass_opaque {}
 pub type PassRef = *Pass_opaque;
 
+pub mod debuginfo {
+    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"]
@@ -929,6 +966,12 @@ pub mod llvm {
         #[fast_ffi]
         pub unsafe fn LLVMDeleteBasicBlock(BB: BasicBlockRef);
 
+        #[fast_ffi]
+        pub unsafe fn LLVMMoveBasicBlockAfter(BB: BasicBlockRef, MoveAfter: BasicBlockRef);
+
+        #[fast_ffi]
+        pub unsafe fn LLVMMoveBasicBlockBefore(BB: BasicBlockRef, MoveBefore: BasicBlockRef);
+
         /* Operations on instructions */
         #[fast_ffi]
         pub unsafe fn LLVMGetInstructionParent(Inst: ValueRef)
@@ -1885,6 +1928,164 @@ pub mod llvm {
                                     AlignStack: Bool, Dialect: c_uint)
                                  -> ValueRef;
 
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderCreate(M: ModuleRef) -> DIBuilderRef;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderDispose(Builder: DIBuilderRef);
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderFinalize(Builder: DIBuilderRef);
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderCreateCompileUnit(
+            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 LLVMDIBuilderCreateFile(
+            Builder: DIBuilderRef,
+            Filename: *c_char,
+            Directory: *c_char) -> DIFile;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderCreateSubroutineType(
+            Builder: DIBuilderRef,
+            File: DIFile,
+            ParameterTypes: DIArray) -> DICompositeType;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderCreateFunction(
+            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 LLVMDIBuilderCreateBasicType(
+            Builder: DIBuilderRef,
+            Name: *c_char,
+            SizeInBits: c_ulonglong,
+            AlignInBits: c_ulonglong,
+            Encoding: c_uint) -> DIBasicType;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderCreatePointerType(
+            Builder: DIBuilderRef,
+            PointeeTy: DIType,
+            SizeInBits: c_ulonglong,
+            AlignInBits: c_ulonglong,
+            Name: *c_char) -> DIDerivedType;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderCreateStructType(
+            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 LLVMDIBuilderCreateMemberType(
+            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 LLVMDIBuilderCreateLexicalBlock(
+            Builder: DIBuilderRef,
+            Scope: DIDescriptor,
+            File: DIFile,
+            Line: c_uint,
+            Col: c_uint) -> DILexicalBlock;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderCreateLocalVariable(
+            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 LLVMDIBuilderCreateArrayType(
+            Builder: DIBuilderRef,
+            Size: c_ulonglong,
+            AlignInBits: c_ulonglong,
+            Ty: DIType,
+            Subscripts: DIArray) -> DIType;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderCreateVectorType(
+            Builder: DIBuilderRef,
+            Size: c_ulonglong,
+            AlignInBits: c_ulonglong,
+            Ty: DIType,
+            Subscripts: DIArray) -> DIType;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderGetOrCreateSubrange(
+            Builder: DIBuilderRef,
+            Lo: c_longlong,
+            Count: c_longlong) -> DISubrange;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderGetOrCreateArray(
+            Builder: DIBuilderRef,
+            Ptr: *DIDescriptor,
+            Count: c_uint) -> DIArray;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderInsertDeclareAtEnd(
+            Builder: DIBuilderRef,
+            Val: ValueRef,
+            VarInfo: DIVariable,
+            InsertAtEnd: BasicBlockRef) -> ValueRef;
+
+        #[fast_ffi]
+        pub unsafe fn LLVMDIBuilderInsertDeclareBefore(
+            Builder: DIBuilderRef,
+            Val: ValueRef,
+            VarInfo: DIVariable,
+            InsertBefore: ValueRef) -> ValueRef;
     }
 }
 
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 53f2729c38e..55fc22a8fcc 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1908,6 +1908,12 @@ pub fn trans_closure(ccx: @mut CrateContext,
     finish(bcx);
     cleanup_and_Br(bcx, bcx_top, fcx.llreturn);
 
+    // Put return block after all other blocks.
+    // This somewhat improves single-stepping experience in debugger.
+    unsafe {
+        llvm::LLVMMoveBasicBlockAfter(fcx.llreturn, bcx.llbb);
+    }
+
     // Insert the mandatory first few basic blocks before lltop.
     finish_fn(fcx, lltop);
 }
@@ -3102,6 +3108,9 @@ 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);
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index 75d7aaa88a6..7aab1d0239e 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -148,7 +148,7 @@ impl CrateContext {
             lib::llvm::associate_type(tn, @"tydesc", tydesc_type);
             let crate_map = decl_crate_map(sess, link_meta, llmod);
             let dbg_cx = if sess.opts.debuginfo {
-                Some(debuginfo::mk_ctxt(name.to_owned()))
+                Some(debuginfo::DebugContext::new(llmod, name.to_owned()))
             } else {
                 None
             };
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 87c33ce64f5..91e3276d8aa 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -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,18 @@ 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::libc::c_uint;
+use core::cmp;
 use core::ptr;
-use core::str;
+use core::str::as_c_str;
 use core::sys;
 use core::vec;
 use syntax::codemap::span;
 use syntax::{ast, codemap, ast_util, ast_map};
 
-static LLVMDebugVersion: int = (9 << 16);
-
 static DW_LANG_RUST: int = 0x9000;
-static DW_VIRTUALITY_none: int = 0;
 
 static CompileUnitTag: int = 17;
 static FileDescriptorTag: int = 41;
@@ -59,302 +56,169 @@ 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::<ValueRef>())
-    }
-}
-
-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,
     names: namegen,
-    crate_file: ~str
-}
-
-pub fn mk_ctxt(crate: ~str) -> DebugContext {
-    DebugContext {
-        llmetadata: @mut HashMap::new(),
-        names: new_namegen(),
-        crate_file: crate
+    crate_file: ~str,
+    llcontext: ContextRef,
+    builder: DIBuilderRef,
+    curr_loc: (uint, uint),
+    created_files: HashMap<~str, DIFile>,
+    created_functions: HashMap<ast::node_id, DISubprogram>,
+    created_blocks: HashMap<ast::node_id, DILexicalBlock>,
+    created_types: HashMap<uint, DIType>
+}
+
+impl DebugContext {
+    pub fn new(llmod: ModuleRef, crate: ~str) -> DebugContext {
+        debug!("DebugContext::new");
+        let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) };
+        // DIBuilder inherits context from the module, so we'd better use the same one
+        let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
+        return DebugContext {
+            names: new_namegen(),
+            crate_file: crate,
+            llcontext: llcontext,
+            builder: builder,
+            curr_loc: (0, 0),
+            created_files: HashMap::new(),
+            created_functions: HashMap::new(),
+            created_blocks: HashMap::new(),
+            created_types: HashMap::new(),
+        };
     }
 }
 
-fn update_cache(cache: metadata_cache, mdtag: int, val: debug_metadata) {
-    let mut existing = match cache.pop(&mdtag) {
-        Some(arr) => arr, None => ~[]
-    };
-    existing.push(val);
-    cache.insert(mdtag, existing);
-}
-
-struct Metadata<T> {
-    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
+#[inline]
+fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext {
+    cx.dbg_cx.get_mut_ref()
 }
 
-type metadata_cache = @mut HashMap<int, ~[debug_metadata]>;
-
-enum debug_metadata {
-    file_metadata(@Metadata<FileMetadata>),
-    compile_unit_metadata(@Metadata<CompileUnitMetadata>),
-    subprogram_metadata(@Metadata<SubProgramMetadata>),
-    local_var_metadata(@Metadata<LocalVarMetadata>),
-    tydesc_metadata(@Metadata<TyDescMetadata>),
-    block_metadata(@Metadata<BlockMetadata>),
-    argument_metadata(@Metadata<ArgumentMetadata>),
-    retval_metadata(@Metadata<RetvalMetadata>),
+#[inline]
+fn DIB(cx: &CrateContext) -> DIBuilderRef {
+    cx.dbg_cx.get_ref().builder
 }
 
-fn cast_safely<T:Copy,U>(val: T) -> U {
+/// Create any deferred debug metadata nodes
+pub fn finalize(cx: @mut CrateContext) {
+    debug!("finalize");
+    create_compile_unit(cx);
     unsafe {
-        let val2 = val;
-        return cast::transmute(val2);
-    }
-}
-
-fn md_from_metadata<T>(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)
-    }
+        llvm::LLVMDIBuilderFinalize(DIB(cx));
+        llvm::LLVMDIBuilderDispose(DIB(cx));
+    };
 }
 
-fn cached_metadata<T:Copy>(cache: metadata_cache,
-                            mdtag: int,
-                            eq_fn: &fn(md: T) -> bool)
-                         -> Option<T> {
-    if cache.contains_key(&mdtag) {
-        let items = cache.get(&mdtag);
-        for items.each |item| {
-            let md: T = md_from_metadata::<T>(*item);
-            if eq_fn(copy md) {
-                return option::Some(copy md);
-            }
-        }
-    }
-    return option::None;
+fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray {
+    return unsafe {
+        llvm::LLVMDIBuilderGetOrCreateArray(builder, vec::raw::to_ptr(arr), arr.len() as u32)
+    };
 }
 
-fn create_compile_unit(cx: &mut CrateContext) -> @Metadata<CompileUnitMetadata> {
-    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<CompileUnitMetadata>>(cache, tg,
-                        |md| md.data.name == crate_name) {
-      option::Some(md) => return md,
-      option::None => ()
+fn create_compile_unit(cx: @mut CrateContext) {
+    let dcx = dbg_cx(cx);
+    let crate_name: &str = dcx.crate_file;
+    let work_dir = cx.sess.working_dir.to_str();
+    let producer = fmt!("rustc version %s", env!("CFG_VERSION"));
+
+    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::LLVMDIBuilderCreateCompileUnit(dcx.builder,
+            DW_LANG_RUST as c_uint, crate_name, work_dir, producer,
+            cx.sess.opts.optimize != session::No,
+            flags, 0, split_name);
+    }}}}}};
+}
+
+fn create_file(cx: @mut CrateContext, full_path: &str) -> DIFile {
+    match dbg_cx(cx).created_files.find_equiv(&full_path) {
+        Some(file_md) => return *file_md,
+        None => ()
     }
 
-    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));
+    debug!("create_file: %s", full_path);
 
-    return mdval;
-}
+    let work_dir = cx.sess.working_dir.to_str();
+    let file_name =
+        if full_path.starts_with(work_dir) {
+            full_path.slice(work_dir.len() + 1u, full_path.len())
+        } else {
+            full_path
+        };
 
-fn get_cache(cx: &CrateContext) -> metadata_cache {
-    cx.dbg_cx.get_ref().llmetadata
-}
+    let file_md =
+        do as_c_str(file_name) |file_name| {
+        do as_c_str(work_dir) |work_dir| { unsafe {
+            llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir)
+        }}};
 
-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())
+    dbg_cx(cx).created_files.insert(full_path.to_owned(), file_md);
+    return file_md;
 }
 
-fn create_file(cx: &mut CrateContext, full_path: ~str)
-    -> @Metadata<FileMetadata> {
-    let cache = get_cache(cx);;
-    let tg = FileDescriptorTag;
-    match cached_metadata::<@Metadata<FileMetadata>>(
-        cache, tg, |md| md.data.path == full_path) {
-        option::Some(md) => return md,
-        option::None => ()
-    }
-
-    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;
+/// Return codemap::Loc corresponding to the beginning of the span
+fn span_start(cx: &CrateContext, span: span) -> codemap::Loc {
+    return cx.sess.codemap.lookup_char_pos(span.lo);
 }
 
-fn line_from_span(cm: @codemap::CodeMap, sp: span) -> uint {
-    cm.lookup_char_pos(sp.lo).line
-}
+fn create_block(bcx: block) -> DILexicalBlock {
+    let mut bcx = bcx;
+    let cx = bcx.ccx();
 
-fn create_block(mut cx: block) -> @Metadata<BlockMetadata> {
-    let cache = get_cache(cx.ccx());
-    while cx.node_info.is_none() {
-        match cx.parent {
-          Some(b) => cx = b,
+    while bcx.node_info.is_none() {
+        match bcx.parent {
+          Some(b) => bcx = b,
           None => fail!()
         }
     }
-    let sp = cx.node_info.get().span;
-
-    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<BlockMetadata>>(
-        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 span = bcx.node_info.get().span;
+    let id = bcx.node_info.get().id;
+
+    match dbg_cx(cx).created_blocks.find(&id) {
+        Some(block) => return *block,
+        None => ()
+    }
+
+    debug!("create_block: %s", bcx.sess().codemap.span_to_str(span));
+
+    let parent = match bcx.parent {
+        None => create_function(bcx.fcx),
+        Some(b) => create_block(b)
     };
-    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
-        }
+    let cx = bcx.ccx();
+    let loc = span_start(cx, span);
+    let file_md = create_file(cx, loc.file.name);
+
+    let block_md = unsafe {
+        llvm::LLVMDIBuilderCreateLexicalBlock(
+            DIB(cx),
+            parent, file_md,
+            loc.line as c_uint, loc.col.to_uint() as c_uint)
     };
-    //update_cache(cache, tg, block_metadata(mdval));
-    return mdval;
+
+    dbg_cx(cx).created_blocks.insert(id, block_md);
+
+    return block_md;
 }
 
-fn size_and_align_of(cx: &mut CrateContext, t: ty::t) -> (int, int) {
+fn size_and_align_of(cx: @mut CrateContext, t: ty::t) -> (uint, uint) {
     let llty = type_of::type_of(cx, t);
-    (machine::llsize_of_real(cx, llty) as int,
-     machine::llalign_of_pref(cx, llty) as int)
+    (machine::llsize_of_real(cx, llty), machine::llalign_of_min(cx, llty))
 }
 
-fn create_basic_type(cx: &mut CrateContext, t: ty::t, span: span)
-    -> @Metadata<TyDescMetadata> {
-    let cache = get_cache(cx);
-    let tg = BasicTypeDescriptorTag;
-    match cached_metadata::<@Metadata<TyDescMetadata>>(
-        cache, tg, |md| ty::type_id(t) == md.data.hash) {
-      option::Some(md) => return md,
-      option::None => ()
+fn create_basic_type(cx: @mut CrateContext, t: ty::t, _span: span) -> DIType {
+    let ty_id = ty::type_id(t);
+    match dbg_cx(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 +242,275 @@ 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(
+                DIB(cx), name,
+                size * 8 as u64, align * 8 as u64, encoding as c_uint)
+        }};
+
+    dbg_cx(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<TyDescMetadata>)
-    -> @Metadata<TyDescMetadata> {
-    let tg = PointerTypeTag;
-    /*let cache = cx.llmetadata;
-    match cached_metadata::<@Metadata<TyDescMetadata>>(
-        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: @mut 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;
-}
-
-struct StructCtxt {
-    file: ValueRef,
-    name: @str,
-    line: int,
-    members: ~[ValueRef],
-    total_size: int,
-    align: int
-}
+    let ptr_md = do as_c_str(name) |name| { unsafe {
+        llvm::LLVMDIBuilderCreatePointerType(DIB(cx),
+                pointee, size * 8 as u64, align * 8 as u64, name)
+    }};
+    return ptr_md;
+}
+
+struct StructContext {
+    builder: DIBuilderRef,
+    file: DIFile,
+    name: ~str,
+    line: uint,
+    members: ~[DIDerivedType],
+    total_size: uint,
+    align: uint
+}
+
+impl StructContext {
+    fn new(cx: &CrateContext, name: ~str, file: DIFile, line: uint) -> ~StructContext {
+        debug!("StructContext::create: %s", name);
+        let scx = ~StructContext {
+            builder: DIB(cx),
+            file: file,
+            name: name,
+            line: line,
+            members: ~[],
+            total_size: 0,
+            align: 1
+        };
+        return scx;
+    }
 
-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));
-}
+    fn add_member(&mut self, name: &str, line: uint, size: uint, align: uint, ty: DIType) {
+        debug!("StructContext(%s)::add_member: %s, size=%u, align=%u",
+                self.name, name, size, align);
+        let offset = roundup(self.total_size, align);
+        let mem_t = do as_c_str(name) |name| { unsafe {
+            llvm::LLVMDIBuilderCreateMemberType(
+                self.builder, ptr::null(), name, self.file, line as c_uint,
+                size * 8 as u64, align * 8 as u64, offset * 8 as u64,
+                0, ty)
+            }};
+        self.members.push(mem_t);
+        self.total_size = offset + size;
+        // struct alignment is the max alignment of its' members
+        self.align = cmp::max(self.align, align);
+    }
 
-fn create_structure(file: @Metadata<FileMetadata>, 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 finalize(&self) -> DICompositeType {
+        debug!("StructContext(%s)::finalize: total_size=%u, align=%u",
+                self.name, self.total_size, self.align);
+        let members_md = create_DIArray(self.builder, self.members);
+
+        let struct_md =
+            do as_c_str(self.name) |name| { unsafe {
+                llvm::LLVMDIBuilderCreateStructType(
+                    self.builder, self.file, name,
+                    self.file, self.line as c_uint,
+                    self.total_size * 8 as u64, self.align * 8 as u64, 0, ptr::null(),
+                    members_md, 0, ptr::null())
+            }};
+        return struct_md;
+    }
 }
 
-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);
+#[inline]
+fn roundup(x: uint, a: uint) -> uint {
+    ((x + (a - 1)) / a) * a
 }
 
-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)
+                -> DICompositeType {
+    let loc = span_start(cx, span);
+    let file_md = create_file(cx, loc.file.name);
 
-fn create_struct(cx: &mut CrateContext, t: ty::t, fields: ~[ty::field],
-                 span: span) -> @Metadata<TyDescMetadata> {
-    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 mut scx = StructContext::new(cx, ty_to_str(cx.tcx, t), file_md, loc.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), loc.line, size, align, ty_md);
     }
-    let mdval = @Metadata {
-        node: finish_structure(scx),
-        data: TyDescMetadata {
-            hash: ty::type_id(t)
-        }
-    };
-    return mdval;
+    return scx.finalize();
 }
 
-fn create_tuple(cx: &mut CrateContext, t: ty::t, elements: &[ty::t], span: span)
-    -> @Metadata<TyDescMetadata> {
-    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);
+// returns (void* type as a ValueRef, size in bytes, align in bytes)
+fn voidptr(cx: @mut CrateContext) -> (DIDerivedType, uint, uint) {
+    let size = sys::size_of::<ValueRef>();
+    let align = sys::min_align_of::<ValueRef>();
+    let vp = do as_c_str("*void") |name| { unsafe {
+            llvm::LLVMDIBuilderCreatePointerType(DIB(cx), ptr::null(),
+                size*8 as u64, align*8 as u64, name)
+        }};
+    return (vp, size, align);
+}
+
+fn create_tuple(cx: @mut CrateContext, _t: ty::t, elements: &[ty::t], span: span)
+                -> DICompositeType {
+    let loc = span_start(cx, span);
+    let file_md = create_file(cx, loc.file.name);
+
+    let name = (cx.sess.str_of((dbg_cx(cx).names)("tuple"))).to_owned();
+    let mut scx = StructContext::new(cx, name, file_md, loc.line);
     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);
+        scx.add_member("", loc.line, size, align, ty_md);
     }
-    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::<ValueRef>() as int;
-    let align = sys::min_align_of::<ValueRef>() as int;
-    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<TyDescMetadata>)
-    -> @Metadata<TyDescMetadata> {
-    //let tg = StructureTypeTag;
-    /*let cache = cx.llmetadata;
-    match cached_metadata::<@Metadata<TyDescMetadata>>(
-        cache, tg, {|md| ty::hash_ty(contents) == ty::hash_ty(md.data.hash)}) {
-      option::Some(md) { return md; }
-      option::None {}
-    }*/
-    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);
+fn create_boxed_type(cx: @mut CrateContext, contents: ty::t,
+                     span: span, boxed: DIType) -> DICompositeType {
+    let loc = span_start(cx, span);
+    let file_md = create_file(cx, loc.file.name);
     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::<uint>() as int,
-               sys::min_align_of::<uint>() as int, refcount_type.node);
+
+    let mut scx = StructContext::new(cx, fmt!("box<%s>", name), file_md, 0);
+    scx.add_member("refcnt", 0, sys::size_of::<uint>(),
+               sys::min_align_of::<uint>(), 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);
+    let (vp, vpsize, vpalign) = voidptr(cx);
+    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;
-}
-
-fn create_composite_type(type_tag: int, name: &str, file: ValueRef,
-                         line: int, size: int, align: int, offset: int,
-                         derived: Option<ValueRef>,
-                         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);
+    scx.add_member("boxed", 0, size, align, boxed);
+    return scx.finalize();
 }
 
-fn create_fixed_vec(cx: &mut CrateContext, vec_t: ty::t, elem_t: ty::t,
-                    len: int, span: span) -> @Metadata<TyDescMetadata> {
-    let t_md = create_ty(cx, elem_t, span);
-    let fname = filename_from_span(cx, span);
-    let file_node = create_file(cx, fname.to_owned());
+fn create_fixed_vec(cx: @mut 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 (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::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0_i64, len as i64)
+    };
+
+    let subscripts = create_DIArray(DIB(cx), [subrange]);
+    return unsafe {
+        llvm::LLVMDIBuilderCreateArrayType(DIB(cx),
+            size * len * 8 as u64, align * 8 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<TyDescMetadata> {
-    let fname = filename_from_span(cx, vec_ty_span);
-    let file_node = create_file(cx, fname.to_owned());
+fn create_boxed_vec(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t,
+                    vec_ty_span: span) -> DICompositeType {
+    let loc = span_start(cx, vec_ty_span);
+    let file_md = create_file(cx, loc.file.name);
     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::new(cx, ty_to_str(cx.tcx, vec_t), file_md, 0);
     let size_t_type = create_basic_type(cx, ty::mk_uint(), vec_ty_span);
-    add_member(vec_scx, "fill", 0, sys::size_of::<libc::size_t>() as int,
-               sys::min_align_of::<libc::size_t>() as int, size_t_type.node);
-    add_member(vec_scx, "alloc", 0, sys::size_of::<libc::size_t>() as int,
-               sys::min_align_of::<libc::size_t>() as int, size_t_type.node);
-    let subrange = llmdnode([lltag(SubrangeTag), lli64(0), lli64(0)]);
+    vec_scx.add_member("fill", 0, sys::size_of::<libc::size_t>(),
+               sys::min_align_of::<libc::size_t>(), size_t_type);
+    vec_scx.add_member("alloc", 0, sys::size_of::<libc::size_t>(),
+               sys::min_align_of::<libc::size_t>(), size_t_type);
+    let subrange = unsafe {
+        llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(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::<u8>() 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 subscripts = create_DIArray(DIB(cx), [subrange]);
+    let data_ptr = unsafe {
+        llvm::LLVMDIBuilderCreateArrayType(DIB(cx),
+            arr_size * 8 as u64, arr_align * 8 as u64, elem_ty_md, subscripts)
     };
+    vec_scx.add_member("data", 0, 0, // clang says the size should be 0
+               sys::min_align_of::<u8>(), data_ptr);
+    let vec_md = vec_scx.finalize();
 
-    let box_scx = create_structure(file_node, (fmt!("box<%s>", name)).to_managed(), 0);
+    let mut box_scx = StructContext::new(cx, fmt!("box<%s>", name), file_md, 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::<uint>() as int,
-               sys::min_align_of::<uint>() as int, refcount_type.node);
-    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::<int>() as int;
-    let align = sys::min_align_of::<int>() 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("refcnt", 0, sys::size_of::<uint>(),
+               sys::min_align_of::<uint>(), refcount_type);
+    let (vp, vpsize, vpalign) = voidptr(cx);
+    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::<int>();
+    let align = sys::min_align_of::<int>();
+    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<TyDescMetadata> {
-    let fname = filename_from_span(cx, span);
-    let file_node = create_file(cx, fname.to_owned());
+fn create_vec_slice(cx: @mut CrateContext, vec_t: ty::t, elem_t: ty::t, span: span)
+                    -> DICompositeType {
+    let loc = span_start(cx, span);
+    let file_md = create_file(cx, loc.file.name);
     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 (_, 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::<uint>() as int,
-               sys::min_align_of::<uint>() 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;
+
+    let mut scx = StructContext::new(cx, ty_to_str(cx.tcx, vec_t), file_md, 0);
+    let (_, ptr_size, ptr_align) = voidptr(cx);
+    scx.add_member("vec", 0, ptr_size, ptr_align, elem_ptr);
+    scx.add_member("length", 0, sys::size_of::<uint>(),
+                    sys::min_align_of::<uint>(), 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<TyDescMetadata> {
-    let fname = filename_from_span(cx, span);
-    let file_node = create_file(cx, fname.to_owned());
-    let (vp, _, _) = voidptr();
+fn create_fn_ty(cx: @mut CrateContext, _fn_ty: ty::t, inputs: ~[ty::t], output: ty::t,
+                span: span) -> DICompositeType {
+    let loc = span_start(cx, span);
+    let file_md = create_file(cx, loc.file.name);
+    let (vp, _, _) = voidptr(cx);
     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::LLVMDIBuilderCreateSubroutineType(DIB(cx), file_md,
+            create_DIArray(DIB(cx), members))
     };
-    return mdval;
 }
 
-fn create_ty(cx: &mut CrateContext, t: ty::t, span: span)
-    -> @Metadata<TyDescMetadata> {
+fn create_unimpl_ty(cx: @mut CrateContext, t: ty::t) -> DIType {
+    let name = ty_to_str(cx.tcx, t);
+    let md = do as_c_str(fmt!("NYI<%s>", name)) |name| { unsafe {
+        llvm::LLVMDIBuilderCreateBasicType(
+            DIB(cx), name,
+            0_u64, 8_u64, DW_ATE_unsigned as c_uint)
+        }};
+    return md;
+}
+
+fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType {
+    let ty_id = ty::type_id(t);
+    match dbg_cx(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<TyDescMetadata>>(
-        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);
@@ -766,7 +522,8 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span)
             }
         },
         ty::ty_enum(_did, ref _substs) => {
-            cx.sess.span_bug(span, "debuginfo for enum NYI")
+            cx.sess.span_note(span, "debuginfo for enum NYI");
+            create_unimpl_ty(cx, t)
         }
         ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => {
             let boxed = create_ty(cx, mt.ty, span);
@@ -776,7 +533,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);
@@ -792,7 +549,8 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span)
             create_pointer_type(cx, t, span, pointee)
         },
         ty::ty_rptr(ref _region, ref _mt) => {
-            cx.sess.span_bug(span, "debuginfo for rptr NYI")
+            cx.sess.span_note(span, "debuginfo for rptr NYI");
+            create_unimpl_ty(cx, t)
         },
         ty::ty_bare_fn(ref barefnty) => {
             let inputs = barefnty.sig.inputs.map(|a| *a);
@@ -800,10 +558,12 @@ fn create_ty(cx: &mut CrateContext, t: ty::t, span: span)
             create_fn_ty(cx, t, inputs, output, span)
         },
         ty::ty_closure(ref _closurety) => {
-            cx.sess.span_bug(span, "debuginfo for closure NYI")
+            cx.sess.span_note(span, "debuginfo for closure NYI");
+            create_unimpl_ty(cx, t)
         },
         ty::ty_trait(_did, ref _substs, ref _vstore, _) => {
-            cx.sess.span_bug(span, "debuginfo for trait NYI")
+            cx.sess.span_note(span, "debuginfo for trait NYI");
+            create_unimpl_ty(cx, t)
         },
         ty::ty_struct(did, ref substs) => {
             let fields = ty::struct_fields(cx.tcx, did, substs);
@@ -812,60 +572,42 @@ 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")
-    }
-}
-
-fn filename_from_span(cx: &CrateContext, sp: codemap::span) -> @str {
-    cx.sess.codemap.lookup_char_pos(sp.lo).file.name
-}
+        _ => cx.sess.bug(~"debuginfo: unexpected type in create_ty")
+    };
 
-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);
+    dbg_cx(cx).created_types.insert(ty_id, ty_md);
+    return ty_md;
 }
 
-pub fn create_local_var(bcx: block, local: @ast::local)
-    -> @Metadata<LocalVarMetadata> {
+pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable {
     let cx = bcx.ccx();
-    let cache = get_cache(cx);
-    let tg = AutoVariableTag;
-    match cached_metadata::<@Metadata<LocalVarMetadata>>(
-        cache, tg, |md| md.data.id == local.node.id) {
-      option::Some(md) => return md,
-      option::None => ()
-    }
 
-    let name = match local.node.pat.node {
+    let ident = 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")
+      _ => {
+        bcx.sess().span_note(local.span, "debuginfo for pattern bindings NYI");
+        return ptr::null();
+      }
     };
-    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, 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));
+
+    let var_md = do as_c_str(name) |name| { unsafe {
+        llvm::LLVMDIBuilderCreateLocalVariable(
+            DIB(cx), AutoVariableTag as u32,
+            context, name, filemd,
+            loc.line as c_uint, tymd, false, 0, 0)
+        }};
 
     // 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) {
@@ -876,59 +618,57 @@ pub fn create_local_var(bcx: block, local: @ast::local)
                 fmt!("No entry in lllocals table for %?", local.node.id));
         }
     };
-    let declargs = ~[llmdnode([llptr]), mdnode];
-    trans::build::Call(bcx, cx.intrinsics.get_copy(&("llvm.dbg.declare")),
-                       declargs);
-    return mdval;
+
+    set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint());
+    unsafe {
+        let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_md, bcx.llbb);
+        llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr);
+    }
+
+    return var_md;
 }
 
-pub fn create_arg(bcx: block, arg: ast::arg, sp: span)
-    -> Option<@Metadata<ArgumentMetadata>> {
+pub fn create_arg(bcx: block, arg: ast::arg, span: span) -> Option<DIVariable> {
+    debug!("create_arg");
+    if true {
+        // XXX create_arg disabled for now because "node_id_type(bcx, arg.id)" below blows
+        // up: "error: internal compiler error: node_id_to_type: no type for node `arg (id=10)`"
+        return None;
+    }
+
     let fcx = bcx.fcx;
     let cx = fcx.ccx;
-    let cache = get_cache(cx);
-    let tg = ArgVariableTag;
-    match cached_metadata::<@Metadata<ArgumentMetadata>>(
-        cache, ArgVariableTag, |md| md.data.id == arg.id) {
-      option::Some(md) => return Some(md),
-      option::None => ()
-    }
 
-    let loc = cx.sess.codemap.lookup_char_pos(sp.lo);
+    let loc = span_start(cx, span);
     if "<intrinsic>" == loc.file.name {
         return None;
     }
+
     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 context = create_function(bcx.fcx);
+    let filemd = create_file(cx, loc.file.name);
+    let context = create_function(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 mdval = @Metadata {
-                node: mdnode,
-                data: ArgumentMetadata {
-                    id: arg.id
-                }
-            };
-            update_cache(cache, tg, argument_metadata(mdval));
+            let ident = path.idents.last();
+            let name: &str = cx.sess.str_of(*ident);
+            let mdnode = do as_c_str(name) |name| { unsafe {
+                llvm::LLVMDIBuilderCreateLocalVariable(DIB(cx),
+                    ArgVariableTag as u32, context, name,
+                    filemd, loc.line as c_uint, tymd, false, 0, 0)
+                    // XXX need to pass in a real argument number
+            }};
 
             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);
+            set_debug_location(cx, create_block(bcx), loc.line, loc.col.to_uint());
+            unsafe {
+                let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
+                        DIB(cx), llptr, mdnode, bcx.llbb);
+                llvm::LLVMSetInstDebugLocation(trans::build::B(bcx), instr);
+            }
+            return Some(mdnode);
         }
         _ => {
             return None;
@@ -936,32 +676,36 @@ 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) {
+fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: uint) {
+    if dbg_cx(cx).curr_loc == (line, col) {
         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);
+    debug!("setting debug location to %u %u", line, col);
+    dbg_cx(cx).curr_loc = (line, col);
+
+    let elems = ~[C_i32(line as i32), C_i32(col as i32), scope, ptr::null()];
     unsafe {
-        llvm::LLVMSetCurrentDebugLocation(trans::build::B(cx), dbgscope);
+        let dbg_loc = llvm::LLVMMDNodeInContext(
+                dbg_cx(cx).llcontext, vec::raw::to_ptr(elems),
+                elems.len() as libc::c_uint);
+        llvm::LLVMSetCurrentDebugLocation(cx.builder.B, dbg_loc);
     }
 }
 
-pub fn create_function(fcx: fn_ctxt) -> @Metadata<SubProgramMetadata> {
-    let mut cx = fcx.ccx;
-
-    debug!("~~");
+/// Set current debug location at the beginning of the span
+pub fn update_source_pos(bcx: block, span: span) {
+    if !bcx.sess().opts.debuginfo || (*span.lo == 0 && *span.hi == 0) {
+        return;
+    }
+    debug!("update_source_pos: %s", bcx.sess().codemap.span_to_str(span));
+    let loc = span_start(bcx.ccx(), span);
+    set_debug_location(bcx.ccx(), create_block(bcx), loc.line, loc.col.to_uint())
+}
 
+pub fn create_function(fcx: fn_ctxt) -> DISubprogram {
+    let cx = fcx.ccx;
     let fcx = &mut *fcx;
-
-    let sp = fcx.span.get();
-    debug!("%s", cx.sess.codemap.span_to_str(sp));
+    let span = fcx.span.get();
 
     let (ident, ret_ty, id) = match cx.tcx.items.get_copy(&fcx.id) {
       ast_map::node_item(item, _) => {
@@ -978,8 +722,7 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata<SubProgramMetadata> {
       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)
+            ((dbg_cx(cx).names)("fn"), decl.output, expr.id)
           }
           _ => fcx.ccx.sess.span_bug(expr.span,
                   "create_function: expected an expr_fn_block here")
@@ -988,62 +731,46 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata<SubProgramMetadata> {
       _ => fcx.ccx.sess.bug("create_function: unexpected sort of node")
     };
 
-    debug!("%?", ident);
-    debug!("%?", id);
-
-    let cache = get_cache(cx);
-    match cached_metadata::<@Metadata<SubProgramMetadata>>(
-        cache, SubprogramTag, |md| md.data.id == id) {
-      option::Some(md) => return md,
-      option::None => ()
+    match dbg_cx(cx).created_functions.find(&id) {
+        Some(fn_md) => return *fn_md,
+        None => ()
     }
 
-    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 {
+    debug!("create_function: %s, %s", cx.sess.str_of(ident), cx.sess.codemap.span_to_str(span));
+
+    let loc = span_start(cx, span);
+    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
-        }
+
+    let fn_ty = unsafe {
+        llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx),
+            file_md, create_DIArray(DIB(cx), [ret_ty_md]))
     };
-    update_cache(cache, SubprogramTag, subprogram_metadata(mdval));
 
-    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(
+                DIB(cx),
+                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(cx).created_functions.insert(id, fn_md);
+    return fn_md;
 }
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index ba87624e2dd..614c1723c5f 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -560,3 +560,228 @@ extern "C" bool LLVMRustStartMultithreading() {
     assert(lock.release());
     return ret;
 }
+
+
+typedef DIBuilder* DIBuilderRef;
+
+template<typename DIT>
+DIT unwrapDI(LLVMValueRef ref) { 
+    return DIT(ref ? unwrap<MDNode>(ref) : NULL); 
+}
+
+extern "C" DIBuilderRef LLVMDIBuilderCreate(LLVMModuleRef M) {
+    return new DIBuilder(*unwrap(M));
+}
+
+extern "C" void LLVMDIBuilderDispose(DIBuilderRef Builder) {
+    delete Builder;
+}
+
+extern "C" void LLVMDIBuilderFinalize(DIBuilderRef Builder) {
+    Builder->finalize();
+}
+
+extern "C" void LLVMDIBuilderCreateCompileUnit(
+    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 LLVMDIBuilderCreateFile(
+    DIBuilderRef Builder,
+    const char* Filename,
+    const char* Directory) {
+    return wrap(Builder->createFile(Filename, Directory));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateSubroutineType(
+    DIBuilderRef Builder,
+    LLVMValueRef File, 
+    LLVMValueRef ParameterTypes) {
+    return wrap(Builder->createSubroutineType(
+        unwrapDI<DIFile>(File), 
+        unwrapDI<DIArray>(ParameterTypes)));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateFunction(
+    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<DIScope>(Scope), Name, LinkageName, 
+        unwrapDI<DIFile>(File), LineNo, 
+        unwrapDI<DIType>(Ty), isLocalToUnit, isDefinition, ScopeLine, 
+        Flags, isOptimized,
+        unwrap<Function>(Fn), 
+        unwrapDI<MDNode*>(TParam),
+        unwrapDI<MDNode*>(Decl)));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateBasicType(
+    DIBuilderRef Builder,
+    const char* Name,
+    uint64_t SizeInBits,
+    uint64_t AlignInBits,
+    unsigned Encoding) {
+    return wrap(Builder->createBasicType(
+        Name, SizeInBits, 
+        AlignInBits, Encoding));
+}
+    
+extern "C" LLVMValueRef LLVMDIBuilderCreatePointerType(
+    DIBuilderRef Builder,
+    LLVMValueRef PointeeTy,
+    uint64_t SizeInBits,
+    uint64_t AlignInBits,
+    const char* Name) {
+    return wrap(Builder->createPointerType(
+        unwrapDI<DIType>(PointeeTy), SizeInBits, AlignInBits, Name));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateStructType(
+    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<DIDescriptor>(Scope), Name, 
+        unwrapDI<DIFile>(File), LineNumber, 
+        SizeInBits, AlignInBits, Flags, 
+        unwrapDI<DIType>(DerivedFrom), 
+        unwrapDI<DIArray>(Elements), RunTimeLang, 
+        unwrapDI<MDNode*>(VTableHolder)));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateMemberType(
+    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<DIDescriptor>(Scope), Name, 
+        unwrapDI<DIFile>(File), LineNo,
+        SizeInBits, AlignInBits, OffsetInBits, Flags, 
+        unwrapDI<DIType>(Ty)));
+}
+    
+extern "C" LLVMValueRef LLVMDIBuilderCreateLexicalBlock(
+    DIBuilderRef Builder,
+    LLVMValueRef Scope,
+    LLVMValueRef File,
+    unsigned Line,
+    unsigned Col) {
+    return wrap(Builder->createLexicalBlock(
+        unwrapDI<DIDescriptor>(Scope), 
+        unwrapDI<DIFile>(File), Line, Col));
+}
+    
+extern "C" LLVMValueRef LLVMDIBuilderCreateLocalVariable(
+    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<DIDescriptor>(Scope), Name, 
+        unwrapDI<DIFile>(File), 
+        LineNo, 
+        unwrapDI<DIType>(Ty), AlwaysPreserve, Flags, ArgNo));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateArrayType(
+    DIBuilderRef Builder,
+    uint64_t Size,  
+    uint64_t AlignInBits,  
+    LLVMValueRef Ty, 
+    LLVMValueRef Subscripts) {
+    return wrap(Builder->createArrayType(Size, AlignInBits,
+        unwrapDI<DIType>(Ty), 
+        unwrapDI<DIArray>(Subscripts)));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderCreateVectorType(
+    DIBuilderRef Builder,
+    uint64_t Size,  
+    uint64_t AlignInBits,  
+    LLVMValueRef Ty, 
+    LLVMValueRef Subscripts) {
+    return wrap(Builder->createVectorType(Size, AlignInBits,
+        unwrapDI<DIType>(Ty), 
+        unwrapDI<DIArray>(Subscripts)));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateSubrange(
+    DIBuilderRef Builder, 
+    int64_t Lo, 
+    int64_t Count) {
+    return wrap(Builder->getOrCreateSubrange(Lo, Count));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderGetOrCreateArray(
+    DIBuilderRef Builder,
+    LLVMValueRef* Ptr, 
+    unsigned Count) {
+    return wrap(Builder->getOrCreateArray(
+        ArrayRef<Value*>(reinterpret_cast<Value**>(Ptr), Count)));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareAtEnd(
+    DIBuilderRef Builder,
+    LLVMValueRef Val,
+    LLVMValueRef VarInfo,
+    LLVMBasicBlockRef InsertAtEnd) {
+    return wrap(Builder->insertDeclare(
+        unwrap(Val), 
+        unwrapDI<DIVariable>(VarInfo), 
+        unwrap(InsertAtEnd)));
+}
+
+extern "C" LLVMValueRef LLVMDIBuilderInsertDeclareBefore(
+    DIBuilderRef Builder,
+    LLVMValueRef Val,
+    LLVMValueRef VarInfo,
+    LLVMValueRef InsertBefore) {
+    return wrap(Builder->insertDeclare(
+        unwrap(Val), 
+        unwrapDI<DIVariable>(VarInfo), 
+        unwrap<Instruction>(InsertBefore)));
+}
diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in
index f5397165781..2a3f7de9bf5 100644
--- a/src/rustllvm/rustllvm.def.in
+++ b/src/rustllvm/rustllvm.def.in
@@ -588,3 +588,22 @@ LLVMInlineAsm
 LLVMInitializePasses
 LLVMAddPass
 LLVMCreatePass
+LLVMDIBuilderCreate
+LLVMDIBuilderDispose
+LLVMDIBuilderFinalize
+LLVMDIBuilderCreateCompileUnit
+LLVMDIBuilderCreateLocalVariable
+LLVMDIBuilderCreateFunction
+LLVMDIBuilderCreateFile
+LLVMDIBuilderCreateLexicalBlock
+LLVMDIBuilderCreateBasicType
+LLVMDIBuilderCreatePointerType
+LLVMDIBuilderCreateMemberType
+LLVMDIBuilderCreateStructType
+LLVMDIBuilderGetOrCreateSubrange
+LLVMDIBuilderCreateArrayType
+LLVMDIBuilderCreateVectorType
+LLVMDIBuilderCreateSubroutineType
+LLVMDIBuilderGetOrCreateArray
+LLVMDIBuilderInsertDeclareAtEnd
+LLVMDIBuilderInsertDeclareBefore
diff --git a/src/rustllvm/rustllvm.h b/src/rustllvm/rustllvm.h
index 6f11202800c..d4202abd285 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"
diff --git a/src/test/debug-info/basic-types.rs b/src/test/debug-info/basic-types.rs
index 20da6b557f1..616740c850c 100644
--- a/src/test/debug-info/basic-types.rs
+++ b/src/test/debug-info/basic-types.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-test
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
 
 // Caveats - gdb prints any 8-bit value (meaning rust i8 and u8 values)
 // as its numerical value along with its associated ASCII char, there
@@ -17,8 +17,9 @@
 // its numerical value.
 
 // compile-flags:-Z extra-debug-info
-// debugger:break 67
+// debugger:break _zzz
 // debugger:run
+// debugger:finish
 // debugger:print b
 // check:$1 = false
 // debugger:print i
@@ -66,5 +67,7 @@ fn main() {
     let f: float = 1.5;
     let f32: f32 = 2.5;
     let f64: f64 = 3.5;
-    let _z = ();
+    _zzz();
 }
+
+fn _zzz() {()}
diff --git a/src/test/debug-info/box.rs b/src/test/debug-info/box.rs
index 54aa0c12578..3e5483ad75b 100644
--- a/src/test/debug-info/box.rs
+++ b/src/test/debug-info/box.rs
@@ -8,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-test
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break 29
+// debugger:break _zzz
 // debugger:run
+// debugger:finish
 // debugger:print a->boxed
 // check:$1 = 1
 // debugger:print b->boxed
@@ -28,5 +29,7 @@ fn main() {
     let b = ~(2, 3.5);
     let c = @4;
     let d = @false;
-    let _z = 0;
+    _zzz();
 }
+
+fn _zzz() {()}
\ No newline at end of file
diff --git a/src/test/debug-info/struct.rs b/src/test/debug-info/struct.rs
index 16ba6cda590..ddfac9cbeea 100644
--- a/src/test/debug-info/struct.rs
+++ b/src/test/debug-info/struct.rs
@@ -8,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-test
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break 29
+// debugger:break _zzz
 // debugger:run
+// debugger:finish
 // debugger:print pair
 // check:$1 = {x = 1, y = 2}
 // debugger:print pair.x
@@ -28,5 +29,7 @@ struct Pair {
 
 fn main() {
     let pair = Pair { x: 1, y: 2 };
-    let _z = ();
+    _zzz();
 }
+
+fn _zzz() {()}
\ No newline at end of file
diff --git a/src/test/debug-info/tuple.rs b/src/test/debug-info/tuple.rs
index 35e2977f562..a50996871ce 100644
--- a/src/test/debug-info/tuple.rs
+++ b/src/test/debug-info/tuple.rs
@@ -8,16 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-test
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break 20
+// debugger:break _zzz
 // debugger:run
+// debugger:finish
 // debugger:print t
 // check:$1 = {4, 5.5, true}
 
 fn main() {
     let t = (4, 5.5, true);
-    let _z = ();
+    _zzz();
 }
+
+fn _zzz() {()}
\ No newline at end of file
diff --git a/src/test/debug-info/vec.rs b/src/test/debug-info/vec.rs
index 3876f1c46d4..c87849ac4b6 100644
--- a/src/test/debug-info/vec.rs
+++ b/src/test/debug-info/vec.rs
@@ -8,12 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// xfail-test
+// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
 
 // compile-flags:-Z extra-debug-info
 // debugger:set print pretty off
-// debugger:break 29
+// debugger:break _zzz
 // debugger:run
+// debugger:finish
 // debugger:print a
 // check:$1 = {1, 2, 3}
 // debugger:print b.vec[0]
@@ -28,5 +29,7 @@ fn main() {
     let b = &[4, 5, 6];
     let c = @[7, 8, 9];
     let d = ~[10, 11, 12];
-    let _z = 0;
+    _zzz();
 }
+
+fn _zzz() {()}
\ No newline at end of file