about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2011-11-10 00:55:09 -0500
committerJosh Matthews <josh@joshmatthews.net>2011-12-18 23:39:54 -0500
commit10030a37d50f5c3ae681709598be201153e0b1e5 (patch)
tree00b9b1e2325dc1300f466fd75fea782509ac3c8b /src/comp
parentfa27724a4bb213f896d4003ed129bf7caff7f3a0 (diff)
downloadrust-10030a37d50f5c3ae681709598be201153e0b1e5.tar.gz
rust-10030a37d50f5c3ae681709598be201153e0b1e5.zip
Generate basic debug info for files, functions and compile units.
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/lib/llvm.rs3
-rw-r--r--src/comp/middle/debuginfo.rs192
-rw-r--r--src/comp/middle/trans.rs11
-rw-r--r--src/comp/middle/trans_common.rs3
-rw-r--r--src/comp/rustc.rc1
5 files changed, 207 insertions, 3 deletions
diff --git a/src/comp/lib/llvm.rs b/src/comp/lib/llvm.rs
index 9ff014699ab..b090fb74644 100644
--- a/src/comp/lib/llvm.rs
+++ b/src/comp/lib/llvm.rs
@@ -256,6 +256,7 @@ native mod llvm {
 
     /* Operations on Users */
     fn LLVMGetOperand(Val: ValueRef, Index: uint) -> ValueRef;
+    fn LLVMSetOperand(Val: ValueRef, Index: uint, Op: ValueRef);
 
     /* Operations on constants of any type */
     fn LLVMConstNull(Ty: TypeRef) -> ValueRef;
@@ -275,6 +276,8 @@ native mod llvm {
     fn LLVMMDNodeInContext(C: ContextRef, Vals: *ValueRef, Count: uint) ->
        ValueRef;
     fn LLVMMDNode(Vals: *ValueRef, Count: uint) -> ValueRef;
+    fn LLVMAddNamedMetadataOperand(M: ModuleRef, Str: sbuf, SLen: uint,
+                                   Val: ValueRef);
 
     /* Operations on scalar constants */
     fn LLVMConstInt(IntTy: TypeRef, N: ULongLong, SignExtend: Bool) ->
diff --git a/src/comp/middle/debuginfo.rs b/src/comp/middle/debuginfo.rs
new file mode 100644
index 00000000000..72390a23383
--- /dev/null
+++ b/src/comp/middle/debuginfo.rs
@@ -0,0 +1,192 @@
+import std::{vec, str, map, option, unsafe};
+import std::vec::to_ptr;
+import std::map::hashmap;
+import lib::llvm::llvm;
+import lib::llvm::llvm::{ModuleRef, ValueRef};
+import middle::trans_common::*;
+import syntax::{ast, codemap};
+
+const LLVMDebugVersion: int = 0x80000;
+
+const DW_LANG_RUST: int = 0x9000;
+const DW_VIRTUALITY_none: int = 0;
+
+const CompileUnitTag: int = 17;
+const FileDescriptorTag: int = 41;
+const SubprogramTag: int = 46;
+
+fn as_buf(s: str) -> str::sbuf {
+    str::as_buf(s, {|sbuf| sbuf})
+}
+fn llstr(s: str) -> ValueRef {
+    llvm::LLVMMDString(as_buf(s), str::byte_len(s))
+}
+
+fn lltag(lltag: int) -> ValueRef {
+    lli32(0x80000 + lltag)
+}
+fn lli32(val: int) -> ValueRef {
+    C_i32(val as i32)
+}
+fn lli1(bval: bool) -> ValueRef {
+    C_bool(bval)
+}
+fn llmdnode(elems: [ValueRef]) -> ValueRef unsafe {
+    llvm::LLVMMDNode(vec::unsafe::to_ptr(elems),
+                     vec::len(elems))
+}
+fn llunused() -> ValueRef {
+    lli32(0x0)
+}
+
+fn update_cache(cache: metadata_cache, mdtag: int, val: debug_metadata) {
+    let existing = if cache.contains_key(mdtag) {
+        cache.get(mdtag)
+    } else {
+        []
+    };
+    cache.insert(mdtag, existing + [val]);
+}
+
+////////////////
+
+type metadata<T> = {node: ValueRef, data: T};
+
+type file_md = {path: str};
+type compile_unit_md = {path: str};
+type subprogram_md = {name: str, file: str};
+
+type metadata_cache = hashmap<int, [debug_metadata]>;
+
+tag debug_metadata {
+    file_metadata(@metadata<file_md>);
+    compile_unit_metadata(@metadata<compile_unit_md>);
+    subprogram_metadata(@metadata<subprogram_md>);
+}
+
+fn md_from_metadata<T>(val: debug_metadata) -> T unsafe {
+    alt val {
+      file_metadata(md) { unsafe::reinterpret_cast(md) }
+      compile_unit_metadata(md) { unsafe::reinterpret_cast(md) }
+      subprogram_metadata(md) { unsafe::reinterpret_cast(md) }
+    }
+}
+
+fn cached_metadata<T>(cache: metadata_cache, mdtag: int,
+                      eq: block(md: T) -> bool) -> option::t<T> {
+    if cache.contains_key(mdtag) {
+        let items = cache.get(mdtag);
+        for item in items {
+            let md: T = md_from_metadata::<T>(item);
+            if eq(md) {
+                ret option::some(md);
+            }
+        }
+    }
+    ret option::none;
+}
+
+fn get_compile_unit_metadata(cx: @crate_ctxt, full_path: str)
+    -> @metadata<compile_unit_md> {
+    let cache = cx.llmetadata;
+    alt cached_metadata::<@metadata<compile_unit_md>>(cache, CompileUnitTag,
+                        {|md| md.data.path == full_path}) {
+      option::some(md) { ret md; }
+      option::none. {}
+    }
+    let sep = str::rindex(full_path, '/' as u8) as uint;
+    let fname = str::slice(full_path, sep + 1u,
+                           str::byte_len(full_path));
+    let path = str::slice(full_path, 0u, sep + 1u);
+    let unit_metadata = [lltag(CompileUnitTag),
+                         llunused(),
+                         lli32(DW_LANG_RUST),
+                         llstr(fname),
+                         llstr(path),
+                         llstr(#env["CFG_VERSION"]),
+                         lli1(false), // main compile unit
+                         lli1(cx.sess.get_opts().optimize != 0u),
+                         llstr(""), // flags (???)
+                         lli32(0) // runtime version (???)
+                         // list of enum types
+                         // list of retained values
+                         // list of subprograms
+                         // list of global variables
+                        ];
+    let unit_node = llmdnode(unit_metadata);
+    llvm::LLVMAddNamedMetadataOperand(cx.llmod, as_buf("llvm.dbg.cu"),
+                                  str::byte_len("llvm.dbg.cu"),
+                                  unit_node);
+    let mdval = @{node: unit_node, data: {path: full_path}};
+    update_cache(cache, CompileUnitTag, compile_unit_metadata(mdval));
+    ret mdval;
+}
+
+//        let kind_id = llvm::LLVMGetMDKindID(as_buf("dbg"),
+//                                            str::byte_len("dbg"));
+
+
+fn get_file_metadata(cx: @crate_ctxt, full_path: str) -> @metadata<file_md> {
+    let cache = cx.llmetadata;
+    alt cached_metadata::<@metadata<file_md>>(
+        cache, FileDescriptorTag, {|md| md.data.path == full_path}) {
+      option::some(md) { ret md; }
+      option::none. {}
+    }
+    let sep = str::rindex(full_path, '/' as u8) as uint;
+    let fname = str::slice(full_path, sep + 1u,
+                           str::byte_len(full_path));
+    let path = str::slice(full_path, 0u, sep + 1u);
+    let unit_node = get_compile_unit_metadata(cx, path).node;
+    let file_md = [lltag(FileDescriptorTag),
+                   llstr(fname),
+                   llstr(path),
+                   unit_node];
+    let val = llmdnode(file_md);
+    let mdval = @{node: val, data: {path: full_path}};
+    update_cache(cache, FileDescriptorTag, file_metadata(mdval));
+    ret mdval;
+}
+
+fn get_function_metadata(cx: @crate_ctxt, item: @ast::item,
+                         llfndecl: ValueRef) -> @metadata<subprogram_md> {
+    let cache = cx.llmetadata;
+    alt cached_metadata::<@metadata<subprogram_md>>(
+        cache, SubprogramTag, {|md| md.data.name == item.ident &&
+                                    /*sub.path == ??*/ true}) {
+      option::some(md) { ret md; }
+      option::none. {}
+    }
+    let loc = codemap::lookup_char_pos(cx.sess.get_codemap(),
+                                           item.span.lo);
+        let file_node = get_file_metadata(cx, loc.filename).node;
+        let fn_metadata = [lltag(SubprogramTag),
+                           llunused(),
+                           file_node,
+                           llstr(item.ident),
+                           llstr(item.ident), //XXX fully-qualified C++ name
+                           llstr(item.ident), //XXX MIPS name?????
+                           file_node,
+                           lli32(loc.line as int),
+                           C_null(T_ptr(T_nil())), // XXX reference to tydesc
+                           lli1(false), //XXX static
+                           lli1(true), // not extern
+                           lli32(DW_VIRTUALITY_none), // virtual-ness
+                           lli32(0i), //index into virt func
+                           C_null(T_ptr(T_nil())), // base type with vtbl
+                           lli1(false), // artificial
+                           lli1(cx.sess.get_opts().optimize != 0u),
+                           llfndecl
+                           //list of template params
+                           //func decl descriptor
+                           //list of func vars
+                          ];
+        let val = llmdnode(fn_metadata);
+        llvm::LLVMAddNamedMetadataOperand(cx.llmod, as_buf("llvm.dbg.sp"),
+                                          str::byte_len("llvm.dbg.sp"),
+                                          val);
+        let mdval = @{node: val, data: {name: item.ident,
+                                        file: loc.filename}};
+        update_cache(cache, SubprogramTag, subprogram_metadata(mdval));
+        ret mdval;
+}
\ No newline at end of file
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index acec464e6f8..6985ef974e6 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -20,7 +20,7 @@ import std::map::{new_int_hash, new_str_hash};
 import option::{some, none};
 import driver::session;
 import front::attr;
-import middle::{ty, gc, resolve};
+import middle::{ty, gc, resolve, debuginfo};
 import middle::freevars::*;
 import back::{link, abi, upcall};
 import syntax::{ast, ast_util};
@@ -4543,6 +4543,12 @@ fn trans_fn(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
     let do_time = cx.ccx.sess.get_opts().stats;
     let start = do_time ? time::get_time() : {sec: 0u32, usec: 0u32};
     trans_closure(cx, sp, f, llfndecl, ty_self, ty_params, id, {|_fcx|});
+    if cx.ccx.sess.get_opts().debuginfo {
+        let item = alt option::get(cx.ccx.ast_map.find(id)) {
+            ast_map::node_item(item) { item }
+        };
+        debuginfo::get_function_metadata(cx.ccx, item, llfndecl);
+    }
     if do_time {
         let end = time::get_time();
         log_fn_time(cx.ccx, str::connect(cx.path, "::"), start, end);
@@ -5659,7 +5665,8 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
           builder: BuilderRef_res(llvm::LLVMCreateBuilder()),
           shape_cx: shape::mk_ctxt(llmod),
           gc_cx: gc::mk_ctxt(),
-          crate_map: crate_map};
+          crate_map: crate_map,
+          llmetadata: map::new_int_hash()};
     let cx = new_local_ctxt(ccx);
     collect_items(ccx, crate);
     collect_tag_ctors(ccx, crate);
diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs
index 19f439235e4..a4f0a6dfe3d 100644
--- a/src/comp/middle/trans_common.rs
+++ b/src/comp/middle/trans_common.rs
@@ -116,7 +116,8 @@ type crate_ctxt =
      builder: BuilderRef_res,
      shape_cx: shape::ctxt,
      gc_cx: gc::ctxt,
-     crate_map: ValueRef};
+     crate_map: ValueRef,
+     llmetadata: debuginfo::metadata_cache};
 
 type local_ctxt =
     {path: [str],
diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc
index 51a01378fb3..9f88b369749 100644
--- a/src/comp/rustc.rc
+++ b/src/comp/rustc.rc
@@ -37,6 +37,7 @@ mod middle {
     mod freevars;
     mod shape;
     mod gc;
+    mod debuginfo;
 
     mod tstate {
         mod ck;