about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-06-26 05:20:06 -0700
committerbors <bors@rust-lang.org>2013-06-26 05:20:06 -0700
commita30ab764e10232d8e9c1f9282c33b65ca9ef7daf (patch)
treec403e0c1216d5307945ea831c245c243b8fb0126
parent4ec05e02fa5f64aaef922948ce00d25f42e0478d (diff)
parent6eb3c0f30daa0db6fc219694a3028917bb1596af (diff)
downloadrust-a30ab764e10232d8e9c1f9282c33b65ca9ef7daf.tar.gz
rust-a30ab764e10232d8e9c1f9282c33b65ca9ef7daf.zip
auto merge of #7255 : michaelwoerister/rust/debuginfo, r=jdm
This PR contains no real code changes. Just some documentation additions in the form of comments and some internal reordering of functions within debuginfo.rs.
-rw-r--r--src/librustc/middle/trans/debuginfo.rs474
1 files changed, 268 insertions, 206 deletions
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 11eecf82bac..dae3d58d2be 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -8,6 +8,39 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+/*!
+# Debug Info Module
+
+This module serves the purpose of generating debug symbols. We use LLVM's
+[source level debugging](http://llvm.org/docs/SourceLevelDebugging.html) features for generating
+the debug information. The general principle is this:
+
+Given the right metadata in the LLVM IR, the LLVM code generator is able to create DWARF debug
+symbols for the given code. The [metadata](http://llvm.org/docs/LangRef.html#metadata-type) is
+structured much like DWARF *debugging information entries* (DIE), representing type information
+such as datatype layout, function signatures, block layout, variable location and scope information,
+etc. It is the purpose of this module to generate correct metadata and insert it into the LLVM IR.
+
+As the exact format of metadata trees may change between different LLVM versions, we now use LLVM
+[DIBuilder](http://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) to create metadata
+where possible. This will hopefully ease the adaption of this module to future LLVM versions.
+
+The public API of the module is a set of functions that will insert the correct metadata into the
+LLVM IR when called with the right parameters. The module is thus driven from an outside client with
+functions like `debuginfo::create_local_var(bcx: block, local: @ast::local)`.
+
+Internally the module will try to reuse already created metadata by utilizing a cache. All private
+state used by the module is stored within a DebugContext struct, which in turn is contained in the
+CrateContext.
+
+
+This file consists of three conceptual sections:
+1. The public interface of the module
+2. Module-internal metadata creation functions
+3. Minor utility functions
+
+*/
+
 use core::prelude::*;
 
 use driver::session;
@@ -34,20 +67,8 @@ use syntax::{ast, codemap, ast_util, ast_map};
 
 static DW_LANG_RUST: int = 0x9000;
 
-static CompileUnitTag: int = 17;
-static FileDescriptorTag: int = 41;
-static SubprogramTag: int = 46;
-static SubroutineTag: int = 21;
-static BasicTypeDescriptorTag: int = 36;
 static AutoVariableTag: int = 256;
 static ArgVariableTag: int = 257;
-static ReturnVariableTag: int = 258;
-static LexicalBlockTag: int = 11;
-static PointerTypeTag: int = 15;
-static StructureTypeTag: int = 19;
-static MemberTag: int = 13;
-static ArrayTypeTag: int = 1;
-static SubrangeTag: int = 33;
 
 static DW_ATE_boolean: int = 0x02;
 static DW_ATE_float: int = 0x04;
@@ -56,8 +77,14 @@ static DW_ATE_signed_char: int = 0x06;
 static DW_ATE_unsigned: int = 0x07;
 static DW_ATE_unsigned_char: int = 0x08;
 
-////////////////
 
+
+
+//=-------------------------------------------------------------------------------------------------
+//  Public Interface of debuginfo module
+//=-------------------------------------------------------------------------------------------------
+
+/// A context object for maintaining all state needed by the debuginfo module.
 pub struct DebugContext {
     names: namegen,
     crate_file: ~str,
@@ -90,16 +117,6 @@ impl DebugContext {
     }
 }
 
-#[inline]
-fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext {
-    cx.dbg_cx.get_mut_ref()
-}
-
-#[inline]
-fn DIB(cx: &CrateContext) -> DIBuilderRef {
-    cx.dbg_cx.get_ref().builder
-}
-
 /// Create any deferred debug metadata nodes
 pub fn finalize(cx: @mut CrateContext) {
     debug!("finalize");
@@ -110,6 +127,207 @@ pub fn finalize(cx: @mut CrateContext) {
     };
 }
 
+/// Creates debug information for the given local variable.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
+/// The return value should be ignored if called from outside of the debuginfo module.
+pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable {
+    let cx = bcx.ccx();
+
+    let ident = match local.node.pat.node {
+      ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth),
+      // FIXME this should be handled (#2533)
+      _ => {
+        bcx.sess().span_note(local.span, "debuginfo for pattern bindings NYI");
+        return ptr::null();
+      }
+    };
+    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, loc.file.name);
+    let context = match bcx.parent {
+        None => create_function(bcx.fcx),
+        Some(_) => create_block(bcx)
+    };
+
+    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) {
+        Some(v) => v,
+        None => {
+            bcx.tcx().sess.span_bug(
+                local.span,
+                fmt!("No entry in lllocals table for %?", local.node.id));
+        }
+    };
+
+    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;
+}
+
+/// Creates debug information for the given function argument.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
+/// The return value should be ignored if called from outside of the debuginfo module.
+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 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, 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 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);
+            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;
+        }
+    }
+}
+
+/// Sets the current debug location at the beginning of the span
+///
+/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...)
+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())
+}
+
+/// Creates debug information for the given function.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
+/// The return value should be ignored if called from outside of the debuginfo module.
+pub fn create_function(fcx: fn_ctxt) -> DISubprogram {
+    let cx = fcx.ccx;
+    let fcx = &mut *fcx;
+    let span = fcx.span.get();
+
+    let (ident, ret_ty, id) = match cx.tcx.items.get_copy(&fcx.id) {
+      ast_map::node_item(item, _) => {
+        match item.node {
+          ast::item_fn(ref decl, _, _, _, _) => {
+            (item.ident, decl.output, item.id)
+          }
+          _ => fcx.ccx.sess.span_bug(item.span, "create_function: item bound to non-function")
+        }
+      }
+      ast_map::node_method(method, _, _) => {
+          (method.ident, method.decl.output, method.id)
+      }
+      ast_map::node_expr(expr) => {
+        match expr.node {
+          ast::expr_fn_block(ref decl, _) => {
+            ((dbg_cx(cx).names)("fn"), decl.output, expr.id)
+          }
+          _ => fcx.ccx.sess.span_bug(expr.span,
+                  "create_function: expected an expr_fn_block here")
+        }
+      }
+      _ => fcx.ccx.sess.bug("create_function: unexpected sort of node")
+    };
+
+    match dbg_cx(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 = 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 => ptr::null(),
+          _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id),
+                         ret_ty.span)
+        }
+    } else {
+        ptr::null()
+    };
+
+    let fn_ty = unsafe {
+        llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx),
+            file_md, create_DIArray(DIB(cx), [ret_ty_md]))
+    };
+
+    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;
+}
+
+
+
+
+//=-------------------------------------------------------------------------------------------------
+// Module-Internal debug info creation functions
+//=-------------------------------------------------------------------------------------------------
+
 fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray {
     return unsafe {
         llvm::LLVMDIBuilderGetOrCreateArray(builder, vec::raw::to_ptr(arr), arr.len() as u32)
@@ -160,10 +378,7 @@ fn create_file(cx: @mut CrateContext, full_path: &str) -> DIFile {
     return file_md;
 }
 
-/// 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 create_block(bcx: block) -> DILexicalBlock {
     let mut bcx = bcx;
@@ -205,10 +420,7 @@ fn create_block(bcx: block) -> DILexicalBlock {
     return block_md;
 }
 
-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), machine::llalign_of_min(cx, llty))
-}
+
 
 fn create_basic_type(cx: @mut CrateContext, t: ty::t, _span: span) -> DIType {
     let ty_id = ty::type_id(t);
@@ -252,6 +464,9 @@ fn create_basic_type(cx: @mut CrateContext, t: ty::t, _span: span) -> DIType {
                 size * 8 as u64, align * 8 as u64, encoding as c_uint)
         }};
 
+    // One could think that this call is not necessary, as the create_ty() function will insert the
+    // type descriptor into the cache anyway. Mind, however, that create_basic_type() is also called
+    // directly from other functions (e.g. create_boxed_type()).
     dbg_cx(cx).created_types.insert(ty_id, ty_md);
     return ty_md;
 }
@@ -324,11 +539,6 @@ impl StructContext {
     }
 }
 
-#[inline]
-fn roundup(x: uint, a: uint) -> uint {
-    ((x + (a - 1)) / a) * a
-}
-
 fn create_struct(cx: @mut CrateContext, t: ty::t, fields: ~[ty::field], span: span)
                 -> DICompositeType {
     let loc = span_start(cx, span);
@@ -579,103 +789,6 @@ fn create_ty(cx: @mut CrateContext, t: ty::t, span: span) -> DIType {
     return ty_md;
 }
 
-pub fn create_local_var(bcx: block, local: @ast::local) -> DIVariable {
-    let cx = bcx.ccx();
-
-    let ident = match local.node.pat.node {
-      ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth),
-      // FIXME this should be handled (#2533)
-      _ => {
-        bcx.sess().span_note(local.span, "debuginfo for pattern bindings NYI");
-        return ptr::null();
-      }
-    };
-    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, loc.file.name);
-    let context = match bcx.parent {
-        None => create_function(bcx.fcx),
-        Some(_) => create_block(bcx)
-    };
-
-    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) {
-        Some(v) => v,
-        None => {
-            bcx.tcx().sess.span_bug(
-                local.span,
-                fmt!("No entry in lllocals table for %?", local.node.id));
-        }
-    };
-
-    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, 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 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, 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 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);
-            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;
-        }
-    }
-}
-
 fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: uint) {
     if dbg_cx(cx).curr_loc == (line, col) {
         return;
@@ -692,85 +805,34 @@ fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: ui
     }
 }
 
-/// 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 span = fcx.span.get();
 
-    let (ident, ret_ty, id) = match cx.tcx.items.get_copy(&fcx.id) {
-      ast_map::node_item(item, _) => {
-        match item.node {
-          ast::item_fn(ref decl, _, _, _, _) => {
-            (item.ident, decl.output, item.id)
-          }
-          _ => fcx.ccx.sess.span_bug(item.span, "create_function: item bound to non-function")
-        }
-      }
-      ast_map::node_method(method, _, _) => {
-          (method.ident, method.decl.output, method.id)
-      }
-      ast_map::node_expr(expr) => {
-        match expr.node {
-          ast::expr_fn_block(ref decl, _) => {
-            ((dbg_cx(cx).names)("fn"), decl.output, expr.id)
-          }
-          _ => fcx.ccx.sess.span_bug(expr.span,
-                  "create_function: expected an expr_fn_block here")
-        }
-      }
-      _ => fcx.ccx.sess.bug("create_function: unexpected sort of node")
-    };
-
-    match dbg_cx(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));
+//=-------------------------------------------------------------------------------------------------
+//  Utility Functions
+//=-------------------------------------------------------------------------------------------------
 
-    let loc = span_start(cx, span);
-    let file_md = create_file(cx, loc.file.name);
+#[inline]
+fn roundup(x: uint, a: uint) -> uint {
+    ((x + (a - 1)) / a) * a
+}
 
-    let ret_ty_md = if cx.sess.opts.extra_debuginfo {
-        match ret_ty.node {
-          ast::ty_nil => ptr::null(),
-          _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id),
-                         ret_ty.span)
-        }
-    } else {
-        ptr::null()
-    };
+/// 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);
+}
 
-    let fn_ty = unsafe {
-        llvm::LLVMDIBuilderCreateSubroutineType(DIB(cx),
-            file_md, create_DIArray(DIB(cx), [ret_ty_md]))
-    };
+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), machine::llalign_of_min(cx, llty))
+}
 
-    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())
-            }}};
+#[inline]
+fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext {
+    cx.dbg_cx.get_mut_ref()
+}
 
-    dbg_cx(cx).created_functions.insert(id, fn_md);
-    return fn_md;
+#[inline]
+fn DIB(cx: &CrateContext) -> DIBuilderRef {
+    cx.dbg_cx.get_ref().builder
 }