1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
14 This module serves the purpose of generating debug symbols. We use LLVM's
15 [source level debugging](http://llvm.org/docs/SourceLevelDebugging.html) features for generating
16 the debug information. The general principle is this:
18 Given the right metadata in the LLVM IR, the LLVM code generator is able to create DWARF debug
19 symbols for the given code. The [metadata](http://llvm.org/docs/LangRef.html#metadata-type) is
20 structured much like DWARF *debugging information entries* (DIE), representing type information
21 such as datatype layout, function signatures, block layout, variable location and scope information,
22 etc. It is the purpose of this module to generate correct metadata and insert it into the LLVM IR.
24 As the exact format of metadata trees may change between different LLVM versions, we now use LLVM
25 [DIBuilder](http://llvm.org/docs/doxygen/html/classllvm_1_1DIBuilder.html) to create metadata
26 where possible. This will hopefully ease the adaption of this module to future LLVM versions.
28 The public API of the module is a set of functions that will insert the correct metadata into the
29 LLVM IR when called with the right parameters. The module is thus driven from an outside client with
30 functions like `debuginfo::local_var_metadata(bcx: block, local: &ast::local)`.
32 Internally the module will try to reuse already created metadata by utilizing a cache. The way to
33 get a shared metadata node when needed is thus to just call the corresponding function in this
36 let file_metadata = file_metadata(crate_context, path);
38 The function will take care of probing the cache for an existing node for that exact file path.
40 All private state used by the module is stored within a DebugContext struct, which in turn is
41 contained in the CrateContext.
44 This file consists of three conceptual sections:
45 1. The public interface of the module
46 2. Module-internal metadata creation functions
47 3. Minor utility functions
54 use lib::llvm::{ModuleRef, ContextRef};
55 use lib::llvm::debuginfo::*;
56 use middle::trans::common::*;
57 use middle::trans::machine;
58 use middle::trans::type_of;
59 use middle::trans::type_::Type;
60 use middle::trans::adt;
63 use util::ppaux::ty_to_str;
65 use std::hashmap::HashMap;
66 use std::libc::{c_uint, c_ulonglong, c_longlong};
69 use syntax::codemap::span;
70 use syntax::{ast, codemap, ast_util, ast_map};
72 static DW_LANG_RUST: int = 0x9000;
74 static DW_TAG_auto_variable: int = 0x100;
75 static DW_TAG_arg_variable: int = 0x101;
77 static DW_ATE_boolean: int = 0x02;
78 static DW_ATE_float: int = 0x04;
79 static DW_ATE_signed: int = 0x05;
80 static DW_ATE_signed_char: int = 0x06;
81 static DW_ATE_unsigned: int = 0x07;
82 static DW_ATE_unsigned_char: int = 0x08;
87 //=-------------------------------------------------------------------------------------------------
88 // Public Interface of debuginfo module
89 //=-------------------------------------------------------------------------------------------------
91 /// A context object for maintaining all state needed by the debuginfo module.
92 pub struct DebugContext {
94 llcontext: ContextRef,
95 builder: DIBuilderRef,
96 curr_loc: (uint, uint),
97 created_files: HashMap<~str, DIFile>,
98 created_functions: HashMap<ast::node_id, DISubprogram>,
99 created_blocks: HashMap<ast::node_id, DILexicalBlock>,
100 created_types: HashMap<uint, DIType>
104 pub fn new(llmod: ModuleRef, crate: ~str) -> DebugContext {
105 debug!("DebugContext::new");
106 let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) };
107 // DIBuilder inherits context from the module, so we'd better use the same one
108 let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
109 return DebugContext {
111 llcontext: llcontext,
114 created_files: HashMap::new(),
115 created_functions: HashMap::new(),
116 created_blocks: HashMap::new(),
117 created_types: HashMap::new(),
122 /// Create any deferred debug metadata nodes
123 pub fn finalize(cx: @mut CrateContext) {
125 compile_unit_metadata(cx);
127 llvm::LLVMDIBuilderFinalize(DIB(cx));
128 llvm::LLVMDIBuilderDispose(DIB(cx));
132 /// Creates debug information for the given local variable.
134 /// Adds the created metadata nodes directly to the crate's IR.
135 /// The return value should be ignored if called from outside of the debuginfo module.
136 pub fn create_local_var_metadata(bcx: @mut Block, local: @ast::Local) -> DIVariable {
139 let ident = match local.pat.node {
140 ast::pat_ident(_, ref pth, _) => ast_util::path_to_ident(pth),
141 // FIXME this should be handled (#2533)
143 bcx.sess().span_note(local.span, "debuginfo for pattern bindings NYI");
148 let name: &str = cx.sess.str_of(ident);
149 debug!("create_local_var_metadata: %s", name);
151 let loc = span_start(cx, local.span);
152 let ty = node_id_type(bcx, local.id);
153 let type_metadata = type_metadata(cx, ty, local.ty.span);
154 let file_metadata = file_metadata(cx, loc.file.name);
156 let context = match bcx.parent {
157 None => create_function_metadata(bcx.fcx),
158 Some(_) => lexical_block_metadata(bcx)
161 let var_metadata = do name.as_c_str |name| {
163 llvm::LLVMDIBuilderCreateLocalVariable(
165 DW_TAG_auto_variable as u32,
177 // FIXME(#6814) Should use `pat_util::pat_bindings` for pats like (a, b) etc
178 let llptr = match bcx.fcx.lllocals.find_copy(&local.pat.id) {
181 bcx.tcx().sess.span_bug(
183 fmt!("No entry in lllocals table for %?", local.id));
187 set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
189 let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(DIB(cx), llptr, var_metadata, bcx.llbb);
190 llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
196 /// Creates debug information for the given function argument.
198 /// Adds the created metadata nodes directly to the crate's IR.
199 /// The return value should be ignored if called from outside of the debuginfo module.
200 pub fn create_argument_metadata(bcx: @mut Block, arg: &ast::arg, span: span) -> Option<DIVariable> {
201 debug!("create_argument_metadata");
203 // XXX create_argument_metadata disabled for now because "node_id_type(bcx, arg.id)" below
205 // "error: internal compiler error: node_id_to_type: no type for node `arg (id=10)`"
212 let loc = span_start(cx, span);
213 if "<intrinsic>" == loc.file.name {
217 let ty = node_id_type(bcx, arg.id);
218 let type_metadata = type_metadata(cx, ty, arg.ty.span);
219 let file_metadata = file_metadata(cx, loc.file.name);
220 let context = create_function_metadata(fcx);
223 ast::pat_ident(_, ref path, _) => {
224 // XXX: This is wrong; it should work for multiple bindings.
225 let ident = path.idents.last();
226 let name: &str = cx.sess.str_of(*ident);
227 let var_metadata = do name.as_c_str |name| {
229 llvm::LLVMDIBuilderCreateLocalVariable(
231 DW_TAG_arg_variable as u32,
240 // XXX need to pass in a real argument number
244 let llptr = fcx.llargs.get_copy(&arg.id);
245 set_debug_location(cx, lexical_block_metadata(bcx), loc.line, loc.col.to_uint());
247 let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
248 DIB(cx), llptr, var_metadata, bcx.llbb);
249 llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr);
251 return Some(var_metadata);
259 /// Sets the current debug location at the beginning of the span
261 /// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...)
262 pub fn update_source_pos(bcx: @mut Block, span: span) {
263 if !bcx.sess().opts.debuginfo || (*span.lo == 0 && *span.hi == 0) {
266 debug!("update_source_pos: %s", bcx.sess().codemap.span_to_str(span));
267 let loc = span_start(bcx.ccx(), span);
268 set_debug_location(bcx.ccx(), lexical_block_metadata(bcx), loc.line, loc.col.to_uint())
271 /// Creates debug information for the given function.
273 /// Adds the created metadata nodes directly to the crate's IR.
274 /// The return value should be ignored if called from outside of the debuginfo module.
275 pub fn create_function_metadata(fcx: &FunctionContext) -> DISubprogram {
277 let span = fcx.span.get();
279 let fnitem = cx.tcx.items.get_copy(&fcx.id);
280 let (ident, ret_ty, id) = match fnitem {
281 ast_map::node_item(ref item, _) => {
283 ast::item_fn(ast::fn_decl { output: ref ty, _}, _, _, _, _) => {
284 (item.ident, ty, item.id)
286 _ => fcx.ccx.sess.span_bug(item.span,
287 "create_function_metadata: item bound to non-function")
290 ast_map::node_method(
292 decl: ast::fn_decl { output: ref ty, _ },
301 ast_map::node_expr(ref expr) => {
303 ast::expr_fn_block(ref decl, _) => {
304 let name = gensym_name("fn");
305 (name, &decl.output, expr.id)
307 _ => fcx.ccx.sess.span_bug(expr.span,
308 "create_function_metadata: expected an expr_fn_block here")
311 ast_map::node_trait_method(
314 decl: ast::fn_decl { output: ref ty, _ },
323 _ => fcx.ccx.sess.bug("create_function_metadata: unexpected sort of node")
326 match dbg_cx(cx).created_functions.find(&id) {
327 Some(fn_metadata) => return *fn_metadata,
331 debug!("create_function_metadata: %s, %s",
332 cx.sess.str_of(ident),
333 cx.sess.codemap.span_to_str(span));
335 let loc = span_start(cx, span);
336 let file_metadata = file_metadata(cx, loc.file.name);
338 let return_type_metadata = if cx.sess.opts.extra_debuginfo {
340 ast::ty_nil => ptr::null(),
341 _ => type_metadata(cx, ty::node_id_to_type(cx.tcx, id), ret_ty.span)
348 llvm::LLVMDIBuilderCreateSubroutineType(
351 create_DIArray(DIB(cx), [return_type_metadata]))
355 do cx.sess.str_of(ident).as_c_str |name| {
356 do cx.sess.str_of(ident).as_c_str |linkage| {
358 llvm::LLVMDIBuilderCreateFunction(
369 FlagPrototyped as c_uint,
370 cx.sess.opts.optimize != session::No,
377 dbg_cx(cx).created_functions.insert(id, fn_metadata);
384 //=-------------------------------------------------------------------------------------------------
385 // Module-Internal debug info creation functions
386 //=-------------------------------------------------------------------------------------------------
388 fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray {
390 llvm::LLVMDIBuilderGetOrCreateArray(builder, vec::raw::to_ptr(arr), arr.len() as u32)
394 fn compile_unit_metadata(cx: @mut CrateContext) {
395 let dcx = dbg_cx(cx);
396 let crate_name: &str = dcx.crate_file;
398 debug!("compile_unit_metadata: %?", crate_name);
400 let work_dir = cx.sess.working_dir.to_str();
401 let producer = fmt!("rustc version %s", env!("CFG_VERSION"));
403 do crate_name.as_c_str |crate_name| {
404 do work_dir.as_c_str |work_dir| {
405 do producer.as_c_str |producer| {
406 do "".as_c_str |flags| {
407 do "".as_c_str |split_name| {
409 llvm::LLVMDIBuilderCreateCompileUnit(dcx.builder,
410 DW_LANG_RUST as c_uint, crate_name, work_dir, producer,
411 cx.sess.opts.optimize != session::No,
412 flags, 0, split_name);
417 fn file_metadata(cx: &mut CrateContext, full_path: &str) -> DIFile {
418 match dbg_cx(cx).created_files.find_equiv(&full_path) {
419 Some(file_metadata) => return *file_metadata,
423 debug!("file_metadata: %s", full_path);
425 let work_dir = cx.sess.working_dir.to_str();
427 if full_path.starts_with(work_dir) {
428 full_path.slice(work_dir.len() + 1u, full_path.len())
434 do file_name.as_c_str |file_name| {
435 do work_dir.as_c_str |work_dir| {
437 llvm::LLVMDIBuilderCreateFile(DIB(cx), file_name, work_dir)
441 dbg_cx(cx).created_files.insert(full_path.to_owned(), file_metadata);
442 return file_metadata;
445 /// Get or create the lexical block metadata node for the given LLVM basic block.
446 fn lexical_block_metadata(bcx: @mut Block) -> DILexicalBlock {
450 // Search up the tree of basic blocks until we find one that knows the containing lexical block.
451 while bcx.node_info.is_none() {
454 None => cx.sess.bug("debuginfo: Could not find lexical block for LLVM basic block.")
458 let span = bcx.node_info.get().span;
459 let id = bcx.node_info.get().id;
461 // Check whether we already have a cache entry for this node id
462 match dbg_cx(cx).created_blocks.find(&id) {
463 Some(block) => return *block,
467 debug!("lexical_block_metadata: %s", bcx.sess().codemap.span_to_str(span));
469 let parent = match bcx.parent {
470 None => create_function_metadata(bcx.fcx),
471 Some(b) => lexical_block_metadata(b)
474 let loc = span_start(cx, span);
475 let file_metadata = file_metadata(cx, loc.file.name);
477 let lexical_block_metadata = unsafe {
478 llvm::LLVMDIBuilderCreateLexicalBlock(
483 loc.col.to_uint() as c_uint)
486 dbg_cx(cx).created_blocks.insert(id, lexical_block_metadata);
488 return lexical_block_metadata;
491 fn basic_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType {
493 debug!("basic_type_metadata: %?", ty::get(t));
495 let (name, encoding) = match ty::get(t).sty {
496 ty::ty_nil | ty::ty_bot => (~"uint", DW_ATE_unsigned),
497 ty::ty_bool => (~"bool", DW_ATE_boolean),
498 ty::ty_int(int_ty) => match int_ty {
499 ast::ty_i => (~"int", DW_ATE_signed),
500 ast::ty_char => (~"char", DW_ATE_signed_char),
501 ast::ty_i8 => (~"i8", DW_ATE_signed),
502 ast::ty_i16 => (~"i16", DW_ATE_signed),
503 ast::ty_i32 => (~"i32", DW_ATE_signed),
504 ast::ty_i64 => (~"i64", DW_ATE_signed)
506 ty::ty_uint(uint_ty) => match uint_ty {
507 ast::ty_u => (~"uint", DW_ATE_unsigned),
508 ast::ty_u8 => (~"u8", DW_ATE_unsigned),
509 ast::ty_u16 => (~"u16", DW_ATE_unsigned),
510 ast::ty_u32 => (~"u32", DW_ATE_unsigned),
511 ast::ty_u64 => (~"u64", DW_ATE_unsigned)
513 ty::ty_float(float_ty) => match float_ty {
514 ast::ty_f => (~"float", DW_ATE_float),
515 ast::ty_f32 => (~"f32", DW_ATE_float),
516 ast::ty_f64 => (~"f64", DW_ATE_float)
518 _ => cx.sess.bug("debuginfo::basic_type_metadata - t is invalid type")
521 let llvm_type = type_of::type_of(cx, t);
522 let (size, align) = size_and_align_of(cx, llvm_type);
523 let ty_metadata = do name.as_c_str |name| {
525 llvm::LLVMDIBuilderCreateBasicType(
529 bytes_to_bits(align),
537 fn pointer_type_metadata(cx: &mut CrateContext,
539 pointee_type_metadata: DIType)
541 let pointer_llvm_type = type_of::type_of(cx, pointer_type);
542 let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
543 let name = ty_to_str(cx.tcx, pointer_type);
544 let ptr_metadata = do name.as_c_str |name| {
546 llvm::LLVMDIBuilderCreatePointerType(
548 pointee_type_metadata,
549 bytes_to_bits(pointer_size),
550 bytes_to_bits(pointer_align),
557 fn struct_metadata(cx: &mut CrateContext,
559 fields: ~[ty::field],
562 let struct_name = ty_to_str(cx.tcx, struct_type);
563 debug!("struct_metadata: %s", struct_name);
565 let struct_llvm_type = type_of::type_of(cx, struct_type);
567 let field_llvm_types = do fields.map |field| { type_of::type_of(cx, field.mt.ty) };
568 let field_names = do fields.map |field| { cx.sess.str_of(field.ident).to_owned() };
569 let field_types_metadata = do fields.map |field| {
570 type_metadata(cx, field.mt.ty, span)
573 return composite_type_metadata(
579 field_types_metadata,
583 fn tuple_metadata(cx: &mut CrateContext,
585 component_types: &[ty::t],
589 let tuple_name = ty_to_str(cx.tcx, tuple_type);
590 let tuple_llvm_type = type_of::type_of(cx, tuple_type);
592 let component_names = do component_types.map |_| { ~"" };
593 let component_llvm_types = do component_types.map |it| { type_of::type_of(cx, *it) };
594 let component_types_metadata = do component_types.map |it| {
595 type_metadata(cx, *it, span)
598 return composite_type_metadata(
602 component_llvm_types,
604 component_types_metadata,
608 fn enum_metadata(cx: &mut CrateContext,
610 enum_def_id: ast::def_id,
611 // _substs is only needed in the other version. Will go away with new snapshot.
612 _substs: &ty::substs,
616 let enum_name = ty_to_str(cx.tcx, enum_type);
618 // For empty enums there is an early exit. Just describe it as an empty struct with the
619 // appropriate type name
620 if ty::type_is_empty(cx.tcx, enum_type) {
621 return composite_type_metadata(cx, Type::nil(), enum_name, [], [], [], span);
624 // Prepare some data (llvm type, size, align, ...) about the discriminant. This data will be
625 // needed in all of the following cases.
626 let discriminant_llvm_type = Type::enum_discrim(cx);
627 let (discriminant_size, discriminant_align) = size_and_align_of(cx, discriminant_llvm_type);
629 assert!(Type::enum_discrim(cx) == cx.int_type);
630 let discriminant_type_metadata = type_metadata(cx, ty::mk_int(), span);
632 let variants: &[@ty::VariantInfo] = *ty::enum_variants(cx.tcx, enum_def_id);
634 let enumerators_metadata: ~[DIDescriptor] = variants
637 let name: &str = cx.sess.str_of(v.name);
638 let discriminant_value = v.disr_val as c_ulonglong;
640 do name.as_c_str |name| {
642 llvm::LLVMDIBuilderCreateEnumerator(
651 let loc = span_start(cx, span);
652 let file_metadata = file_metadata(cx, loc.file.name);
654 let discriminant_type_metadata = do enum_name.as_c_str |enum_name| {
656 llvm::LLVMDIBuilderCreateEnumerationType(
662 bytes_to_bits(discriminant_size),
663 bytes_to_bits(discriminant_align),
664 create_DIArray(DIB(cx), enumerators_metadata),
665 discriminant_type_metadata)
669 let type_rep = adt::represent_type(cx, enum_type);
673 return discriminant_type_metadata;
675 adt::Univariant(ref struct_def, _) => {
676 assert!(variants.len() == 1);
677 return adt_struct_metadata(cx, struct_def, variants[0], None, span);
679 adt::General(ref struct_defs) => {
680 let variants_member_metadata: ~[DIDescriptor] = do struct_defs
683 .transform |(i, struct_def)| {
684 let variant_type_metadata = adt_struct_metadata(
688 Some(discriminant_type_metadata),
691 do "".as_c_str |name| {
693 llvm::LLVMDIBuilderCreateMemberType(
699 bytes_to_bits(struct_def.size as uint),
700 bytes_to_bits(struct_def.align as uint),
703 variant_type_metadata)
708 let enum_llvm_type = type_of::type_of(cx, enum_type);
709 let (enum_type_size, enum_type_align) = size_and_align_of(cx, enum_llvm_type);
711 return do enum_name.as_c_str |enum_name| {
713 llvm::LLVMDIBuilderCreateUnionType(
719 bytes_to_bits(enum_type_size),
720 bytes_to_bits(enum_type_align),
722 create_DIArray(DIB(cx), variants_member_metadata),
726 adt::NullablePointer { nonnull: ref struct_def, nndiscr, _ } => {
727 return adt_struct_metadata(cx, struct_def, variants[nndiscr], None, span);
731 fn adt_struct_metadata(cx: &mut CrateContext,
732 struct_def: &adt::Struct,
733 variant_info: &ty::VariantInfo,
734 discriminant_type_metadata: Option<DIType>,
738 let arg_llvm_types: ~[Type] = do struct_def.fields.map |&ty| { type_of::type_of(cx, ty) };
739 let arg_metadata: ~[DIType] = do struct_def.fields.iter().enumerate()
740 .transform |(i, &ty)| {
741 match discriminant_type_metadata {
742 Some(metadata) if i == 0 => metadata,
743 _ => type_metadata(cx, ty, span)
747 let mut arg_names = match variant_info.arg_names {
748 Some(ref names) => do names.map |ident| { cx.sess.str_of(*ident).to_owned() },
749 None => do variant_info.args.map |_| { ~"" }
752 if discriminant_type_metadata.is_some() {
753 arg_names.insert(0, ~"");
756 let variant_llvm_type = Type::struct_(arg_llvm_types, struct_def.packed);
757 let variant_name: &str = cx.sess.str_of(variant_info.name);
759 return composite_type_metadata(
770 /// Creates debug information for a composite type, that is, anything that results in a LLVM struct.
772 /// Examples of Rust types to use this are: structs, tuples, boxes, vecs, and enums.
773 fn composite_type_metadata(cx: &mut CrateContext,
774 composite_llvm_type: Type,
775 composite_type_name: &str,
776 member_llvm_types: &[Type],
777 member_names: &[~str],
778 member_type_metadata: &[DIType],
782 let loc = span_start(cx, span);
783 let file_metadata = file_metadata(cx, loc.file.name);
785 let (composite_size, composite_align) = size_and_align_of(cx, composite_llvm_type);
787 let member_metadata: ~[DIDescriptor] = member_llvm_types
790 .transform(|(i, &member_llvm_type)| {
791 let (member_size, member_align) = size_and_align_of(cx, member_llvm_type);
792 let member_offset = machine::llelement_offset(cx, composite_llvm_type, i);
793 let member_name: &str = member_names[i];
795 do member_name.as_c_str |member_name| {
797 llvm::LLVMDIBuilderCreateMemberType(
803 bytes_to_bits(member_size),
804 bytes_to_bits(member_align),
805 bytes_to_bits(member_offset),
807 member_type_metadata[i])
813 return do composite_type_name.as_c_str |name| {
815 llvm::LLVMDIBuilderCreateStructType(
821 bytes_to_bits(composite_size),
822 bytes_to_bits(composite_align),
825 create_DIArray(DIB(cx), member_metadata),
832 fn boxed_type_metadata(cx: &mut CrateContext,
833 content_type_name: Option<&str>,
834 content_llvm_type: Type,
835 content_type_metadata: DIType,
839 let box_type_name = match content_type_name {
840 Some(content_type_name) => fmt!("Boxed<%s>", content_type_name),
844 let box_llvm_type = Type::box(cx, &content_llvm_type);
845 let member_llvm_types = box_llvm_type.field_types();
846 let member_names = [~"refcnt", ~"tydesc", ~"prev", ~"next", ~"val"];
848 assert!(box_layout_is_correct(cx, member_llvm_types, content_llvm_type));
850 let int_type = ty::mk_int();
851 let nil_pointer_type = ty::mk_nil_ptr(cx.tcx);
853 let member_types_metadata = [
854 type_metadata(cx, int_type, span),
855 type_metadata(cx, nil_pointer_type, span),
856 type_metadata(cx, nil_pointer_type, span),
857 type_metadata(cx, nil_pointer_type, span),
858 content_type_metadata
861 return composite_type_metadata(
867 member_types_metadata,
870 // Unfortunately, we cannot assert anything but the correct types here---and not whether the
871 // 'next' and 'prev' pointers are in the correct order.
872 fn box_layout_is_correct(cx: &CrateContext,
873 member_llvm_types: &[Type],
874 content_llvm_type: Type)
876 member_llvm_types.len() == 5 &&
877 member_llvm_types[0] == cx.int_type &&
878 member_llvm_types[1] == cx.tydesc_type.ptr_to() &&
879 member_llvm_types[2] == Type::i8().ptr_to() &&
880 member_llvm_types[3] == Type::i8().ptr_to() &&
881 member_llvm_types[4] == content_llvm_type
885 fn fixed_vec_metadata(cx: &mut CrateContext,
890 let element_type_metadata = type_metadata(cx, element_type, span);
891 let element_llvm_type = type_of::type_of(cx, element_type);
892 let (element_type_size, element_type_align) = size_and_align_of(cx, element_llvm_type);
894 let subrange = unsafe {
895 llvm::LLVMDIBuilderGetOrCreateSubrange(
901 let subscripts = create_DIArray(DIB(cx), [subrange]);
903 llvm::LLVMDIBuilderCreateArrayType(
905 bytes_to_bits(element_type_size * len),
906 bytes_to_bits(element_type_align),
907 element_type_metadata,
912 fn vec_metadata(cx: &mut CrateContext,
917 let element_type_metadata = type_metadata(cx, element_type, span);
918 let element_llvm_type = type_of::type_of(cx, element_type);
919 let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
921 let vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type);
922 let vec_type_name: &str = fmt!("[%s]", ty_to_str(cx.tcx, element_type));
924 let member_llvm_types = vec_llvm_type.field_types();
925 let member_names = &[~"fill", ~"alloc", ~"elements"];
927 let int_type_metadata = type_metadata(cx, ty::mk_int(), span);
928 let array_type_metadata = unsafe {
929 llvm::LLVMDIBuilderCreateArrayType(
931 bytes_to_bits(element_size),
932 bytes_to_bits(element_align),
933 element_type_metadata,
934 create_DIArray(DIB(cx), [llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, 0)]))
937 // fill alloc elements
938 let member_type_metadata = &[int_type_metadata, int_type_metadata, array_type_metadata];
940 return composite_type_metadata(
946 member_type_metadata,
950 fn boxed_vec_metadata(cx: &mut CrateContext,
955 let element_llvm_type = type_of::type_of(cx, element_type);
956 let vec_llvm_type = Type::vec(cx.sess.targ_cfg.arch, &element_llvm_type);
957 let vec_type_name: &str = fmt!("[%s]", ty_to_str(cx.tcx, element_type));
958 let vec_metadata = vec_metadata(cx, element_type, span);
960 return boxed_type_metadata(
968 fn vec_slice_metadata(cx: &mut CrateContext,
974 debug!("vec_slice_metadata: %?", ty::get(vec_type));
976 let slice_llvm_type = type_of::type_of(cx, vec_type);
977 let slice_type_name = ty_to_str(cx.tcx, vec_type);
979 let member_llvm_types = slice_llvm_type.field_types();
980 let member_names = &[~"data_ptr", ~"size_in_bytes"];
982 assert!(slice_layout_is_correct(cx, member_llvm_types, element_type));
984 let data_ptr_type = ty::mk_ptr(cx.tcx, ty::mt { ty: element_type, mutbl: ast::m_imm });
986 let member_type_metadata = &[type_metadata(cx, data_ptr_type, span),
987 type_metadata(cx, ty::mk_uint(), span)];
989 return composite_type_metadata(
995 member_type_metadata,
998 fn slice_layout_is_correct(cx: &mut CrateContext,
999 member_llvm_types: &[Type],
1000 element_type: ty::t)
1002 member_llvm_types.len() == 2 &&
1003 member_llvm_types[0] == type_of::type_of(cx, element_type).ptr_to() &&
1004 member_llvm_types[1] == cx.int_type
1008 fn bare_fn_metadata(cx: &mut CrateContext,
1013 -> DICompositeType {
1015 debug!("bare_fn_metadata: %?", ty::get(_fn_ty));
1017 let loc = span_start(cx, span);
1018 let file_metadata = file_metadata(cx, loc.file.name);
1020 let nil_pointer_type_metadata = type_metadata(cx, ty::mk_nil_ptr(cx.tcx), span);
1021 let output_metadata = type_metadata(cx, output, span);
1022 let output_ptr_metadata = pointer_type_metadata(cx, output, output_metadata);
1024 let inputs_vals = do inputs.map |arg| { type_metadata(cx, *arg, span) };
1025 let members = ~[output_ptr_metadata, nil_pointer_type_metadata] + inputs_vals;
1028 llvm::LLVMDIBuilderCreateSubroutineType(
1031 create_DIArray(DIB(cx), members))
1035 fn unimplemented_type_metadata(cx: &mut CrateContext, t: ty::t) -> DIType {
1036 debug!("unimplemented_type_metadata: %?", ty::get(t));
1038 let name = ty_to_str(cx.tcx, t);
1039 let metadata = do fmt!("NYI<%s>", name).as_c_str |name| {
1041 llvm::LLVMDIBuilderCreateBasicType(
1046 DW_ATE_unsigned as c_uint)
1053 fn type_metadata(cx: &mut CrateContext,
1057 let type_id = ty::type_id(t);
1058 match dbg_cx(cx).created_types.find(&type_id) {
1059 Some(type_metadata) => return *type_metadata,
1063 fn create_pointer_to_box_metadata(cx: &mut CrateContext,
1064 pointer_type: ty::t,
1068 let content_type_name: &str = ty_to_str(cx.tcx, type_in_box);
1069 let content_llvm_type = type_of::type_of(cx, type_in_box);
1070 let content_type_metadata = type_metadata(
1073 codemap::dummy_sp());
1075 let box_metadata = boxed_type_metadata(
1077 Some(content_type_name),
1079 content_type_metadata,
1080 codemap::dummy_sp());
1082 pointer_type_metadata(cx, pointer_type, box_metadata)
1085 debug!("type_metadata: %?", ty::get(t));
1087 let sty = &ty::get(t).sty;
1088 let type_metadata = match *sty {
1094 ty::ty_float(_) => {
1095 basic_type_metadata(cx, t)
1097 ty::ty_estr(ref vstore) => {
1098 let i8_t = ty::mk_i8();
1100 ty::vstore_fixed(len) => {
1101 fixed_vec_metadata(cx, i8_t, len + 1, span)
1103 ty::vstore_uniq => {
1104 let vec_metadata = vec_metadata(cx, i8_t, span);
1105 pointer_type_metadata(cx, t, vec_metadata)
1108 let boxed_vec_metadata = boxed_vec_metadata(cx, i8_t, span);
1109 pointer_type_metadata(cx, t, boxed_vec_metadata)
1111 ty::vstore_slice(_region) => {
1112 vec_slice_metadata(cx, t, i8_t, span)
1116 ty::ty_enum(def_id, ref substs) => {
1117 enum_metadata(cx, t, def_id, substs, span)
1119 ty::ty_box(ref mt) => {
1120 create_pointer_to_box_metadata(cx, t, mt.ty)
1122 ty::ty_evec(ref mt, ref vstore) => {
1124 ty::vstore_fixed(len) => {
1125 fixed_vec_metadata(cx, mt.ty, len, span)
1127 ty::vstore_uniq if ty::type_contents(cx.tcx, mt.ty).contains_managed() => {
1128 let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, span);
1129 pointer_type_metadata(cx, t, boxed_vec_metadata)
1131 ty::vstore_uniq => {
1132 let vec_metadata = vec_metadata(cx, mt.ty, span);
1133 pointer_type_metadata(cx, t, vec_metadata)
1136 let boxed_vec_metadata = boxed_vec_metadata(cx, mt.ty, span);
1137 pointer_type_metadata(cx, t, boxed_vec_metadata)
1139 ty::vstore_slice(_) => {
1140 vec_slice_metadata(cx, t, mt.ty, span)
1144 ty::ty_uniq(ref mt) if ty::type_contents(cx.tcx, mt.ty).contains_managed() => {
1145 create_pointer_to_box_metadata(cx, t, mt.ty)
1147 ty::ty_uniq(ref mt) |
1148 ty::ty_ptr(ref mt) |
1149 ty::ty_rptr(_, ref mt) => {
1150 let pointee = type_metadata(cx, mt.ty, span);
1151 pointer_type_metadata(cx, t, pointee)
1153 ty::ty_bare_fn(ref barefnty) => {
1154 let inputs = barefnty.sig.inputs.map(|a| *a);
1155 let output = barefnty.sig.output;
1156 bare_fn_metadata(cx, t, inputs, output, span)
1158 ty::ty_closure(ref _closurety) => {
1159 cx.sess.span_note(span, "debuginfo for closure NYI");
1160 unimplemented_type_metadata(cx, t)
1162 ty::ty_trait(_did, ref _substs, ref _vstore, _, _bounds) => {
1163 cx.sess.span_note(span, "debuginfo for trait NYI");
1164 unimplemented_type_metadata(cx, t)
1166 ty::ty_struct(did, ref substs) => {
1167 let fields = ty::struct_fields(cx.tcx, did, substs);
1168 struct_metadata(cx, t, fields, span)
1170 ty::ty_tup(ref elements) => {
1171 tuple_metadata(cx, t, *elements, span)
1173 _ => cx.sess.bug("debuginfo: unexpected type in type_metadata")
1176 dbg_cx(cx).created_types.insert(type_id, type_metadata);
1177 return type_metadata;
1180 fn set_debug_location(cx: @mut CrateContext, scope: DIScope, line: uint, col: uint) {
1181 if dbg_cx(cx).curr_loc == (line, col) {
1184 debug!("setting debug location to %u %u", line, col);
1185 dbg_cx(cx).curr_loc = (line, col);
1187 let elems = ~[C_i32(line as i32), C_i32(col as i32), scope, ptr::null()];
1189 let dbg_loc = llvm::LLVMMDNodeInContext(
1190 dbg_cx(cx).llcontext,
1191 vec::raw::to_ptr(elems),
1192 elems.len() as c_uint);
1194 llvm::LLVMSetCurrentDebugLocation(cx.builder.B, dbg_loc);
1199 //=-------------------------------------------------------------------------------------------------
1200 // Utility Functions
1201 //=-------------------------------------------------------------------------------------------------
1204 fn roundup(x: uint, a: uint) -> uint {
1205 ((x + (a - 1)) / a) * a
1208 /// Return codemap::Loc corresponding to the beginning of the span
1209 fn span_start(cx: &CrateContext, span: span) -> codemap::Loc {
1210 cx.sess.codemap.lookup_char_pos(span.lo)
1213 fn size_and_align_of(cx: &mut CrateContext, llvm_type: Type) -> (uint, uint) {
1214 (machine::llsize_of_alloc(cx, llvm_type), machine::llalign_of_min(cx, llvm_type))
1217 fn bytes_to_bits(bytes: uint) -> c_ulonglong {
1218 (bytes * 8) as c_ulonglong
1222 fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext {
1223 cx.dbg_cx.get_mut_ref()
1227 fn DIB(cx: &CrateContext) -> DIBuilderRef {
1228 cx.dbg_cx.get_ref().builder