debuginfo.rs 29.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
use core::prelude::*;
12

13
use driver::session;
P
Patrick Walton 已提交
14
use lib::llvm::ValueRef;
15 16 17 18 19
use lib::llvm::llvm;
use middle::pat_util::*;
use middle::trans::base;
use middle::trans::build::B;
use middle::trans::common::*;
20 21 22
use middle::trans::shape;
use middle::trans::type_of;
use middle::trans;
P
Patrick Walton 已提交
23 24
use middle::ty;
use util::ppaux::ty_to_str;
25

26 27 28
use core::libc;
use core::option;
use core::sys;
29 30 31 32 33 34
use std::map::HashMap;
use std::map;
use syntax::ast::Ty;
use syntax::codemap::{span, CharPos};
use syntax::parse::token::ident_interner;
use syntax::{ast, codemap, ast_util, ast_map};
35

36 37 38 39 40
export create_local_var;
export create_function;
export create_arg;
export update_source_pos;
export debug_ctxt;
41
export mk_ctxt;
42

43
const LLVMDebugVersion: int = (9 << 16);
44 45 46 47 48 49 50

const DW_LANG_RUST: int = 0x9000;
const DW_VIRTUALITY_none: int = 0;

const CompileUnitTag: int = 17;
const FileDescriptorTag: int = 41;
const SubprogramTag: int = 46;
51
const SubroutineTag: int = 21;
52 53 54 55 56
const BasicTypeDescriptorTag: int = 36;
const AutoVariableTag: int = 256;
const ArgVariableTag: int = 257;
const ReturnVariableTag: int = 258;
const LexicalBlockTag: int = 11;
57 58 59
const PointerTypeTag: int = 15;
const StructureTypeTag: int = 19;
const MemberTag: int = 13;
J
Josh Matthews 已提交
60 61
const ArrayTypeTag: int = 1;
const SubrangeTag: int = 33;
62 63 64 65 66 67 68

const DW_ATE_boolean: int = 0x02;
const DW_ATE_float: int = 0x04;
const DW_ATE_signed: int = 0x05;
const DW_ATE_signed_char: int = 0x06;
const DW_ATE_unsigned: int = 0x07;
const DW_ATE_unsigned_char: int = 0x08;
69

70
fn llstr(s: ~str) -> ValueRef {
B
Brian Anderson 已提交
71
    str::as_c_str(s, |sbuf| {
72 73 74
        unsafe {
            llvm::LLVMMDString(sbuf, str::len(s) as libc::c_uint)
        }
75
    })
76 77
}
fn lltag(lltag: int) -> ValueRef {
78
    lli32(LLVMDebugVersion | lltag)
79 80 81 82
}
fn lli32(val: int) -> ValueRef {
    C_i32(val as i32)
}
83 84 85
fn lli64(val: int) -> ValueRef {
    C_i64(val as i64)
}
86 87 88
fn lli1(bval: bool) -> ValueRef {
    C_bool(bval)
}
89
fn llmdnode(elems: ~[ValueRef]) -> ValueRef unsafe {
90 91 92 93
    unsafe {
        llvm::LLVMMDNode(vec::raw::to_ptr(elems),
                         vec::len(elems) as libc::c_uint)
    }
94 95 96 97
}
fn llunused() -> ValueRef {
    lli32(0x0)
}
98
fn llnull() -> ValueRef unsafe {
99
    cast::reinterpret_cast(&ptr::null::<ValueRef>())
100
}
101

102
fn add_named_metadata(cx: @crate_ctxt, name: ~str, val: ValueRef) {
B
Brian Anderson 已提交
103
    str::as_c_str(name, |sbuf| {
104 105 106
        unsafe {
            llvm::LLVMAddNamedMetadataOperand(cx.llmod, sbuf, val)
        }
107
    })
108 109 110 111
}

////////////////

J
Josh Matthews 已提交
112 113
type debug_ctxt = {
    llmetadata: metadata_cache,
114
    names: namegen,
115
    crate_file: ~str
J
Josh Matthews 已提交
116 117
};

118
fn mk_ctxt(+crate: ~str, intr: @ident_interner) -> debug_ctxt {
119
    {llmetadata: map::HashMap(),
P
Paul Stansifer 已提交
120
     names: new_namegen(intr),
121 122 123
     crate_file: crate}
}

124 125 126 127
fn update_cache(cache: metadata_cache, mdtag: int, val: debug_metadata) {
    let existing = if cache.contains_key(mdtag) {
        cache.get(mdtag)
    } else {
128
        ~[]
129
    };
130
    cache.insert(mdtag, vec::append_one(existing, val));
131
}
J
Josh Matthews 已提交
132

133 134
type metadata<T> = {node: ValueRef, data: T};

135 136
type file_md = {path: ~str};
type compile_unit_md = {name: ~str};
137
type subprogram_md = {id: ast::node_id};
138 139
type local_var_md = {id: ast::node_id};
type tydesc_md = {hash: uint};
140
type block_md = {start: codemap::Loc, end: codemap::Loc};
141 142
type argument_md = {id: ast::node_id};
type retval_md = {id: ast::node_id};
143

B
Brian Anderson 已提交
144
type metadata_cache = HashMap<int, ~[debug_metadata]>;
145

P
Patrick Walton 已提交
146
enum debug_metadata {
P
Patrick Walton 已提交
147 148 149 150 151 152 153 154
    file_metadata(@metadata<file_md>),
    compile_unit_metadata(@metadata<compile_unit_md>),
    subprogram_metadata(@metadata<subprogram_md>),
    local_var_metadata(@metadata<local_var_md>),
    tydesc_metadata(@metadata<tydesc_md>),
    block_metadata(@metadata<block_md>),
    argument_metadata(@metadata<argument_md>),
    retval_metadata(@metadata<retval_md>),
155 156
}

157
fn cast_safely<T: Copy, U>(val: T) -> U unsafe {
158
    let val2 = val;
159
    return cast::transmute(move val2);
160 161 162
}

fn md_from_metadata<T>(val: debug_metadata) -> T unsafe {
163
    match val {
B
Brian Anderson 已提交
164 165 166 167 168 169 170 171
      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)
172 173 174
    }
}

175
fn cached_metadata<T: Copy>(cache: metadata_cache, mdtag: int,
B
Brian Anderson 已提交
176
                           eq: fn(md: T) -> bool) -> Option<T> unsafe {
177 178
    if cache.contains_key(mdtag) {
        let items = cache.get(mdtag);
B
Brian Anderson 已提交
179
        for items.each |item| {
180
            let md: T = md_from_metadata::<T>(*item);
181
            if eq(md) {
B
Brian Anderson 已提交
182
                return option::Some(md);
183 184 185
            }
        }
    }
B
Brian Anderson 已提交
186
    return option::None;
187 188
}

189
fn create_compile_unit(cx: @crate_ctxt)
K
Kevin Cantu 已提交
190
    -> @metadata<compile_unit_md> unsafe {
J
Josh Matthews 已提交
191
    let cache = get_cache(cx);
192
    let crate_name = /*bad*/copy (/*bad*/copy cx.dbg_cx).get().crate_file;
193
    let tg = CompileUnitTag;
194
    match cached_metadata::<@metadata<compile_unit_md>>(cache, tg,
B
Brian Anderson 已提交
195
                        |md| md.data.name == crate_name) {
B
Brian Anderson 已提交
196 197
      option::Some(md) => return md,
      option::None => ()
198
    }
199

200
    let (_, work_dir) = get_file_path_and_dir(cx.sess.working_dir.to_str(),
201
                                              crate_name);
202
    let unit_metadata = ~[lltag(tg),
203 204
                         llunused(),
                         lli32(DW_LANG_RUST),
205
                         llstr(copy crate_name),
206
                         llstr(work_dir),
P
Paul Stansifer 已提交
207
                         llstr(env!("CFG_VERSION")),
208
                         lli1(true), // deprecated: main compile unit
209
                         lli1(cx.sess.opts.optimize != session::No),
210
                         llstr(~""), // flags (???)
211
                         lli32(0) // runtime version (???)
212
                        ];
213
    let unit_node = llmdnode(unit_metadata);
214
    add_named_metadata(cx, ~"llvm.dbg.cu", unit_node);
215
    let mdval = @{node: unit_node, data: {name: crate_name}};
216
    update_cache(cache, tg, compile_unit_metadata(mdval));
217

B
Brian Anderson 已提交
218
    return mdval;
219 220
}

221
fn get_cache(cx: @crate_ctxt) -> metadata_cache {
222
    (/*bad*/copy cx.dbg_cx).get().llmetadata
J
Josh Matthews 已提交
223 224
}

225
fn get_file_path_and_dir(work_dir: &str, full_path: &str) -> (~str, ~str) {
226 227 228 229
    (if str::starts_with(full_path, work_dir) {
        str::slice(full_path, str::len(work_dir) + 1u,
                   str::len(full_path))
    } else {
230 231
        str::from_slice(full_path)
    }, str::from_slice(work_dir))
232 233
}

234
fn create_file(cx: @crate_ctxt, +full_path: ~str) -> @metadata<file_md> {
J
Josh Matthews 已提交
235 236
    let cache = get_cache(cx);;
    let tg = FileDescriptorTag;
237
    match cached_metadata::<@metadata<file_md>>(
B
Brian Anderson 已提交
238
        cache, tg, |md| md.data.path == full_path) {
B
Brian Anderson 已提交
239 240
        option::Some(md) => return md,
        option::None => ()
241
    }
242

243 244 245
    let (file_path, work_dir) =
        get_file_path_and_dir(cx.sess.working_dir.to_str(),
                              full_path);
246
    let unit_node = create_compile_unit(cx).node;
247
    let file_md = ~[lltag(tg),
248 249
                   llstr(file_path),
                   llstr(work_dir),
250
                   unit_node];
251 252
    let val = llmdnode(file_md);
    let mdval = @{node: val, data: {path: full_path}};
J
Josh Matthews 已提交
253
    update_cache(cache, tg, file_metadata(mdval));
B
Brian Anderson 已提交
254
    return mdval;
255 256
}

257
fn line_from_span(cm: @codemap::CodeMap, sp: span) -> uint {
B
Brian Anderson 已提交
258
    cm.lookup_char_pos(sp.lo).line
J
Josh Matthews 已提交
259 260
}

261
fn create_block(cx: block) -> @metadata<block_md> {
262
    let cache = get_cache(cx.ccx());
263
    let mut cx = cx;
B
Brian Anderson 已提交
264
    while cx.node_info.is_none() {
265
        match cx.parent {
B
Brian Anderson 已提交
266 267
          Some(b) => cx = b,
          None => fail
268 269
        }
    }
B
Brian Anderson 已提交
270
    let sp = cx.node_info.get().span;
271

B
Brian Anderson 已提交
272
    let start = cx.sess().codemap.lookup_char_pos(sp.lo);
273
    let fname = /*bad*/copy start.file.name;
B
Brian Anderson 已提交
274
    let end = cx.sess().codemap.lookup_char_pos(sp.hi);
J
Josh Matthews 已提交
275
    let tg = LexicalBlockTag;
276
    /*match cached_metadata::<@metadata<block_md>>(
J
Josh Matthews 已提交
277
        cache, tg,
278
        {|md| start == md.data.start && end == md.data.end}) {
B
Brian Anderson 已提交
279 280
      option::Some(md) { return md; }
      option::None {}
281
    }*/
282

283
    let parent = match cx.parent {
B
Brian Anderson 已提交
284 285
        None => create_function(cx.fcx).node,
        Some(bcx) => create_block(bcx).node
286
    };
287
    let file_node = create_file(cx.ccx(), fname);
288
    let unique_id = match cache.find(LexicalBlockTag) {
B
Brian Anderson 已提交
289 290
      option::Some(v) => vec::len(v) as int,
      option::None => 0
291
    };
292
    let lldata = ~[lltag(tg),
293
                  parent,
294 295
                  lli32(start.line.to_int()),
                  lli32(start.col.to_int()),
296 297
                  file_node.node,
                  lli32(unique_id)
298
                 ];
299 300 301
    let val = llmdnode(lldata);
    let mdval = @{node: val, data: {start: start, end: end}};
    //update_cache(cache, tg, block_metadata(mdval));
B
Brian Anderson 已提交
302
    return mdval;
303 304
}

305
fn size_and_align_of(cx: @crate_ctxt, t: ty::t) -> (int, int) {
306 307
    let llty = type_of::type_of(cx, t);
    (shape::llsize_of_real(cx, llty) as int,
308
     shape::llalign_of_pref(cx, llty) as int)
309 310
}

311
fn create_basic_type(cx: @crate_ctxt, t: ty::t, span: span)
312
    -> @metadata<tydesc_md> {
J
Josh Matthews 已提交
313
    let cache = get_cache(cx);
314
    let tg = BasicTypeDescriptorTag;
315
    match cached_metadata::<@metadata<tydesc_md>>(
B
Brian Anderson 已提交
316
        cache, tg, |md| ty::type_id(t) == md.data.hash) {
B
Brian Anderson 已提交
317 318
      option::Some(md) => return md,
      option::None => ()
319
    }
320

321
    let (name, encoding) = (~"uint", DW_ATE_unsigned);
322

323
    let fname = filename_from_span(cx, span);
324
    let file_node = create_file(cx, fname);
325
    let cu_node = create_compile_unit(cx);
326
    let (size, align) = size_and_align_of(cx, t);
327
    let lldata = ~[lltag(tg),
328
                  cu_node.node,
329
                  llstr(name),
330
                  file_node.node,
331 332 333
                  lli32(0), //XXX source line
                  lli64(size * 8),  // size in bits
                  lli64(align * 8), // alignment in bits
334
                  lli64(0), //XXX offset?
335
                  lli32(0), //XXX flags?
336
                  lli32(encoding)];
337
    let llnode = llmdnode(lldata);
338
    let mdval = @{node: llnode, data: {hash: ty::type_id(t)}};
339
    update_cache(cache, tg, tydesc_metadata(mdval));
340
    add_named_metadata(cx, ~"llvm.dbg.ty", llnode);
B
Brian Anderson 已提交
341
    return mdval;
342 343
}

344
fn create_pointer_type(cx: @crate_ctxt, t: ty::t, span: span,
345
                       pointee: @metadata<tydesc_md>)
346 347 348
    -> @metadata<tydesc_md> {
    let tg = PointerTypeTag;
    /*let cache = cx.llmetadata;
349
    match cached_metadata::<@metadata<tydesc_md>>(
350
        cache, tg, {|md| ty::hash_ty(t) == ty::hash_ty(md.data.hash)}) {
B
Brian Anderson 已提交
351 352
      option::Some(md) { return md; }
      option::None {}
353
    }*/
354
    let (size, align) = size_and_align_of(cx, t);
355
    let fname = filename_from_span(cx, span);
356 357
    let file_node = create_file(cx, fname);
    //let cu_node = create_compile_unit(cx, fname);
358
    let llnode = create_derived_type(tg, file_node.node, ~"", 0, size * 8,
359
                                     align * 8, 0, pointee.node);
360
    let mdval = @{node: llnode, data: {hash: ty::type_id(t)}};
361
    //update_cache(cache, tg, tydesc_metadata(mdval));
362
    add_named_metadata(cx, ~"llvm.dbg.ty", llnode);
B
Brian Anderson 已提交
363
    return mdval;
364 365
}

J
Josh Matthews 已提交
366 367
type struct_ctxt = {
    file: ValueRef,
368
    name: ~str,
J
Josh Matthews 已提交
369
    line: int,
370
    mut members: ~[ValueRef],
G
Graydon Hoare 已提交
371
    mut total_size: int,
J
Josh Matthews 已提交
372 373 374 375
    align: int
};

fn finish_structure(cx: @struct_ctxt) -> ValueRef {
376 377 378 379 380 381 382 383 384 385 386 387
    return create_composite_type(StructureTypeTag,
                                 /*bad*/copy cx.name,
                                 cx.file,
                                 cx.line,
                                 cx.total_size,
                                 cx.align,
                                 0,
                                 option::None,
                                 option::Some(/*bad*/copy cx.members));
}

fn create_structure(file: @metadata<file_md>, +name: ~str, line: int)
J
Josh Matthews 已提交
388 389 390 391
    -> @struct_ctxt {
    let cx = @{file: file.node,
               name: name,
               line: line,
392
               mut members: ~[],
G
Graydon Hoare 已提交
393
               mut total_size: 0,
J
Josh Matthews 已提交
394
               align: 64 //XXX different alignment per arch?
J
Josh Matthews 已提交
395
              };
B
Brian Anderson 已提交
396
    return cx;
J
Josh Matthews 已提交
397 398
}

399
fn create_derived_type(type_tag: int, file: ValueRef, +name: ~str, line: int,
400 401
                       size: int, align: int, offset: int, ty: ValueRef)
    -> ValueRef {
402
    let lldata = ~[lltag(type_tag),
403
                  file,
J
Josh Matthews 已提交
404
                  llstr(name),
405
                  file,
J
Josh Matthews 已提交
406
                  lli32(line),
407 408 409
                  lli64(size),
                  lli64(align),
                  lli64(offset),
J
Josh Matthews 已提交
410
                  lli32(0),
411
                  ty];
B
Brian Anderson 已提交
412
    return llmdnode(lldata);
413 414
}

415
fn add_member(cx: @struct_ctxt, +name: ~str, line: int, size: int, align: int,
416
              ty: ValueRef) {
417
    cx.members.push(create_derived_type(MemberTag, cx.file, name, line,
J
Josh Matthews 已提交
418
                                       size * 8, align * 8, cx.total_size,
419
                                       ty));
J
Josh Matthews 已提交
420 421 422
    cx.total_size += size * 8;
}

423
fn create_record(cx: @crate_ctxt, t: ty::t, fields: ~[ast::ty_field],
424
                 span: span) -> @metadata<tydesc_md> {
J
Josh Matthews 已提交
425
    let fname = filename_from_span(cx, span);
426
    let file_node = create_file(cx, fname);
J
Josh Matthews 已提交
427
    let scx = create_structure(file_node,
P
Paul Stansifer 已提交
428
                               cx.sess.str_of(
429 430
                                   ((/*bad*/copy cx.dbg_cx).get().names)
                                   (~"rec")),
431
                               line_from_span(cx.sess.codemap,
J
Josh Matthews 已提交
432
                                              span) as int);
B
Brian Anderson 已提交
433
    for fields.each |field| {
434
        let field_t = ty::get_field(cx.tcx, t, field.node.ident).mt.ty;
435
        let ty_md = create_ty(cx, field_t, field.node.mt.ty);
436
        let (size, align) = size_and_align_of(cx, field_t);
P
Paul Stansifer 已提交
437
        add_member(scx, cx.sess.str_of(field.node.ident),
438
                   line_from_span(cx.sess.codemap, field.span) as int,
J
Josh Matthews 已提交
439 440
                   size as int, align as int, ty_md.node);
    }
441
    let mdval = @{node: finish_structure(scx), data:{hash: ty::type_id(t)}};
B
Brian Anderson 已提交
442
    return mdval;
J
Josh Matthews 已提交
443 444
}

445
fn create_boxed_type(cx: @crate_ctxt, outer: ty::t, _inner: ty::t,
446
                     span: span, boxed: @metadata<tydesc_md>)
447
    -> @metadata<tydesc_md> {
448
    //let tg = StructureTypeTag;
449
    /*let cache = cx.llmetadata;
450
    match cached_metadata::<@metadata<tydesc_md>>(
451
        cache, tg, {|md| ty::hash_ty(outer) == ty::hash_ty(md.data.hash)}) {
B
Brian Anderson 已提交
452 453
      option::Some(md) { return md; }
      option::None {}
454 455
    }*/
    let fname = filename_from_span(cx, span);
456 457
    let file_node = create_file(cx, fname);
    //let cu_node = create_compile_unit_metadata(cx, fname);
458
    let uint_t = ty::mk_uint(cx.tcx);
459
    let refcount_type = create_basic_type(cx, uint_t, span);
460
    let scx = create_structure(file_node, ty_to_str(cx.tcx, outer), 0);
461
    add_member(scx, ~"refcnt", 0, sys::size_of::<uint>() as int,
462
               sys::min_align_of::<uint>() as int, refcount_type.node);
463
    add_member(scx, ~"boxed", 0, 8, //XXX member_size_and_align(??)
J
Josh Matthews 已提交
464
               8, //XXX just a guess
J
Josh Matthews 已提交
465 466
               boxed.node);
    let llnode = finish_structure(scx);
467
    let mdval = @{node: llnode, data: {hash: ty::type_id(outer)}};
468
    //update_cache(cache, tg, tydesc_metadata(mdval));
469
    add_named_metadata(cx, ~"llvm.dbg.ty", llnode);
B
Brian Anderson 已提交
470
    return mdval;
471 472
}

473 474
fn create_composite_type(type_tag: int, +name: ~str, file: ValueRef,
                         line: int, size: int, align: int, offset: int,
B
Brian Anderson 已提交
475
                         derived: Option<ValueRef>,
476
                         +members: Option<~[ValueRef]>)
J
Josh Matthews 已提交
477
    -> ValueRef {
478
    let lldata = ~[lltag(type_tag),
J
Josh Matthews 已提交
479 480 481 482 483 484
                  file,
                  llstr(name), // type name
                  file, // source file definition
                  lli32(line), // source line definition
                  lli64(size), // size of members
                  lli64(align), // align
485
                  lli32/*64*/(offset), // offset
J
Josh Matthews 已提交
486
                  lli32(0), // flags
B
Brian Anderson 已提交
487
                  if derived.is_none() {
488 489
                      llnull()
                  } else { // derived from
B
Brian Anderson 已提交
490
                      derived.get()
491
                  },
B
Brian Anderson 已提交
492
                  if members.is_none() {
493 494
                      llnull()
                  } else { //members
B
Brian Anderson 已提交
495
                      llmdnode(members.get())
496
                  },
J
Josh Matthews 已提交
497 498
                  lli32(0),  // runtime language
                  llnull()
499
                 ];
B
Brian Anderson 已提交
500
    return llmdnode(lldata);
J
Josh Matthews 已提交
501 502
}

503
fn create_vec(cx: @crate_ctxt, vec_t: ty::t, elem_t: ty::t,
504
              vec_ty_span: codemap::span, elem_ty: @ast::Ty)
J
Josh Matthews 已提交
505
    -> @metadata<tydesc_md> {
T
Tim Chevalier 已提交
506
    let fname = filename_from_span(cx, vec_ty_span);
507 508
    let file_node = create_file(cx, fname);
    let elem_ty_md = create_ty(cx, elem_t, elem_ty);
509
    let scx = create_structure(file_node, ty_to_str(cx.tcx, vec_t), 0);
510
    let size_t_type = create_basic_type(cx, ty::mk_uint(cx.tcx), vec_ty_span);
511
    add_member(scx, ~"fill", 0, sys::size_of::<libc::size_t>() as int,
512
               sys::min_align_of::<libc::size_t>() as int, size_t_type.node);
513
    add_member(scx, ~"alloc", 0, sys::size_of::<libc::size_t>() as int,
514
               sys::min_align_of::<libc::size_t>() as int, size_t_type.node);
515
    let subrange = llmdnode(~[lltag(SubrangeTag), lli64(0), lli64(0)]);
516
    let (arr_size, arr_align) = size_and_align_of(cx, elem_t);
517
    let data_ptr = create_composite_type(ArrayTypeTag, ~"", file_node.node, 0,
J
Josh Matthews 已提交
518
                                         arr_size, arr_align, 0,
B
Brian Anderson 已提交
519 520
                                         option::Some(elem_ty_md.node),
                                         option::Some(~[subrange]));
521
    add_member(scx, ~"data", 0, 0, // clang says the size should be 0
522
               sys::min_align_of::<u8>() as int, data_ptr);
J
Josh Matthews 已提交
523
    let llnode = finish_structure(scx);
B
Brian Anderson 已提交
524
    return @{node: llnode, data: {hash: ty::type_id(vec_t)}};
J
Josh Matthews 已提交
525 526
}

527
fn create_ty(_cx: @crate_ctxt, _t: ty::t, _ty: @ast::Ty)
J
Josh Matthews 已提交
528
    -> @metadata<tydesc_md> {
J
Josh Matthews 已提交
529
    /*let cache = get_cache(cx);
530
    match cached_metadata::<@metadata<tydesc_md>>(
J
Josh Matthews 已提交
531
        cache, tg, {|md| t == md.data.hash}) {
B
Brian Anderson 已提交
532 533
      option::Some(md) { return md; }
      option::None {}
J
Josh Matthews 已提交
534 535
    }*/

536
    /* FIXME (#2012): disabled this code as part of the patch that moves
537 538 539 540 541 542 543 544 545 546 547 548
     * recognition of named builtin types into resolve. I tried to fix
     * it, but it seems to already be broken -- it's only called when
     * --xg is given, and compiling with --xg fails on trivial programs.
     *
     * Generating an ast::ty from a ty::t seems like it should not be
     * needed. It is only done to track spans, but you will not get the
     * right spans anyway -- types tend to refer to stuff defined
     * elsewhere, not be self-contained.
     */

    fail;
    /*
549
    fn t_to_ty(cx: crate_ctxt, t: ty::t, span: span) -> @ast::ty {
550
        let ty = match ty::get(t).struct {
551 552 553
          ty::ty_nil { ast::ty_nil }
          ty::ty_bot { ast::ty_bot }
          ty::ty_bool { ast::ty_bool }
554 555 556
          ty::ty_int(t) { ast::ty_int(t) }
          ty::ty_float(t) { ast::ty_float(t) }
          ty::ty_uint(t) { ast::ty_uint(t) }
557
          ty::ty_box(mt) { ast::ty_box({ty: t_to_ty(cx, mt.ty, span),
558
                                        mutbl: mt.mutbl}) }
559
          ty::ty_uniq(mt) { ast::ty_uniq({ty: t_to_ty(cx, mt.ty, span),
560
                                          mutbl: mt.mutbl}) }
J
Josh Matthews 已提交
561
          ty::ty_rec(fields) {
562
            let fs = ~[];
J
Josh Matthews 已提交
563
            for field in fields {
564
                fs.push({node: {ident: field.ident,
J
Josh Matthews 已提交
565
                               mt: {ty: t_to_ty(cx, field.mt.ty, span),
566
                                    mutbl: field.mt.mutbl}},
567
                        span: span});
J
Josh Matthews 已提交
568 569 570
            }
            ast::ty_rec(fs)
          }
J
Josh Matthews 已提交
571
          ty::ty_vec(mt) { ast::ty_vec({ty: t_to_ty(cx, mt.ty, span),
572
                                        mutbl: mt.mutbl}) }
T
Tim Chevalier 已提交
573
          _ {
574
            cx.sess.span_bug(span, "t_to_ty: Can't handle this type");
T
Tim Chevalier 已提交
575
          }
576
        };
B
Brian Anderson 已提交
577
        return @{node: ty, span: span};
578
    }
J
Josh Matthews 已提交
579

580
    match ty.node {
581
      ast::ty_box(mt) {
582
        let inner_t = match ty::get(t).struct {
583
          ty::ty_box(boxed) { boxed.ty }
584
          _ { cx.sess.span_bug(ty.span, "t_to_ty was incoherent"); }
585
        };
586 587
        let md = create_ty(cx, inner_t, mt.ty);
        let box = create_boxed_type(cx, t, inner_t, ty.span, md);
B
Brian Anderson 已提交
588
        return create_pointer_type(cx, t, ty.span, box);
589
      }
590

591
      ast::ty_uniq(mt) {
592
        let inner_t = match ty::get(t).struct {
593
          ty::ty_uniq(boxed) { boxed.ty }
T
Tim Chevalier 已提交
594
          // Hoping we'll have a way to eliminate this check soon.
595
          _ { cx.sess.span_bug(ty.span, "t_to_ty was incoherent"); }
596
        };
597
        let md = create_ty(cx, inner_t, mt.ty);
B
Brian Anderson 已提交
598
        return create_pointer_type(cx, t, ty.span, md);
599
      }
600

601
      ast::ty_infer {
602
        let inferred = t_to_ty(cx, t, ty.span);
B
Brian Anderson 已提交
603
        return create_ty(cx, t, inferred);
604
      }
605

J
Josh Matthews 已提交
606
      ast::ty_rec(fields) {
B
Brian Anderson 已提交
607
        return create_record(cx, t, fields, ty.span);
J
Josh Matthews 已提交
608
      }
609

J
Josh Matthews 已提交
610
      ast::ty_vec(mt) {
611
        let inner_t = ty::sequence_element_type(cx.tcx, t);
T
Tim Chevalier 已提交
612 613
        let inner_ast_t = t_to_ty(cx, inner_t, mt.ty.span);
        let v = create_vec(cx, t, inner_t, ty.span, inner_ast_t);
B
Brian Anderson 已提交
614
        return create_pointer_type(cx, t, ty.span, v);
J
Josh Matthews 已提交
615
      }
616

617
      ast::ty_path(_, id) {
618
        match cx.tcx.def_map.get(id) {
619
          ast::def_prim_ty(pty) {
B
Brian Anderson 已提交
620
            return create_basic_type(cx, t, pty, ty.span);
621 622 623 624 625 626
          }
          _ {}
        }
      }

      _ {}
627
    };
628
    */
629 630
}

631
fn filename_from_span(cx: @crate_ctxt, sp: codemap::span) -> ~str {
632
    /*bad*/copy cx.sess.codemap.lookup_char_pos(sp.lo).file.name
633 634
}

635
fn create_var(type_tag: int, context: ValueRef, +name: ~str, file: ValueRef,
636
              line: int, ret_ty: ValueRef) -> ValueRef {
637
    let lldata = ~[lltag(type_tag),
638 639 640 641 642 643
                  context,
                  llstr(name),
                  file,
                  lli32(line),
                  ret_ty,
                  lli32(0)
644
                 ];
B
Brian Anderson 已提交
645
    return llmdnode(lldata);
646 647
}

648
fn create_local_var(bcx: block, local: @ast::local)
649
    -> @metadata<local_var_md> unsafe {
650
    let cx = bcx.ccx();
J
Josh Matthews 已提交
651
    let cache = get_cache(cx);
652
    let tg = AutoVariableTag;
653
    match cached_metadata::<@metadata<local_var_md>>(
B
Brian Anderson 已提交
654
        cache, tg, |md| md.data.id == local.node.id) {
B
Brian Anderson 已提交
655 656
      option::Some(md) => return md,
      option::None => ()
657
    }
658

659
    let name = match local.node.pat.node {
B
Brian Anderson 已提交
660
      ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth),
T
Tim Chevalier 已提交
661
      // FIXME this should be handled (#2533)
B
Brian Anderson 已提交
662
      _ => fail ~"no single variable name for local"
M
Marijn Haverbeke 已提交
663
    };
B
Brian Anderson 已提交
664
    let loc = cx.sess.codemap.lookup_char_pos(local.span.lo);
665
    let ty = node_id_type(bcx, local.node.id);
666
    let tymd = create_ty(cx, ty, local.node.ty);
667
    let filemd = create_file(cx, /*bad*/copy loc.file.name);
668
    let context = match bcx.parent {
B
Brian Anderson 已提交
669 670
        None => create_function(bcx.fcx).node,
        Some(_) => create_block(bcx).node
671
    };
P
Paul Stansifer 已提交
672
    let mdnode = create_var(tg, context, cx.sess.str_of(name), filemd.node,
673
                            loc.line as int, tymd.node);
674 675
    let mdval = @{node: mdnode, data: {id: local.node.id}};
    update_cache(cache, AutoVariableTag, local_var_metadata(mdval));
676

677
    let llptr = match bcx.fcx.lllocals.find(local.node.id) {
B
Brian Anderson 已提交
678 679
      option::Some(local_mem(v)) => v,
      option::Some(_) => {
680
        bcx.tcx().sess.span_bug(local.span, ~"local is bound to \
T
Tim Chevalier 已提交
681 682
                something weird");
      }
B
Brian Anderson 已提交
683
      option::None => {
684
        match bcx.fcx.lllocals.get(local.node.pat.id) {
B
Brian Anderson 已提交
685 686 687
          local_imm(v) => v,
          _ => bcx.tcx().sess.span_bug(local.span, ~"local is bound to \
                                                     something weird")
688 689 690
        }
      }
    };
691
    let declargs = ~[llmdnode(~[llptr]), mdnode];
692
    trans::build::Call(bcx, cx.intrinsics.get(~"llvm.dbg.declare"),
693
                       declargs);
B
Brian Anderson 已提交
694
    return mdval;
695 696
}

697
fn create_arg(bcx: block, arg: ast::arg, sp: span)
698
    -> Option<@metadata<argument_md>> unsafe {
699
    let fcx = bcx.fcx, cx = fcx.ccx;
J
Josh Matthews 已提交
700
    let cache = get_cache(cx);
701
    let tg = ArgVariableTag;
702
    match cached_metadata::<@metadata<argument_md>>(
B
Brian Anderson 已提交
703
        cache, ArgVariableTag, |md| md.data.id == arg.id) {
704
      option::Some(md) => return Some(md),
B
Brian Anderson 已提交
705
      option::None => ()
706
    }
707

B
Brian Anderson 已提交
708
    let loc = cx.sess.codemap.lookup_char_pos(sp.lo);
709
    let ty = node_id_type(bcx, arg.id);
710
    let tymd = create_ty(cx, ty, arg.ty);
711
    let filemd = create_file(cx, /*bad*/copy loc.file.name);
712
    let context = create_function(bcx.fcx);
713

714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
    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 = @{node: mdnode, data: {id: arg.id}};
            update_cache(cache, tg, argument_metadata(mdval));

            let llptr = match fcx.llargs.get(arg.id) {
              local_mem(v) | local_imm(v) => v,
            };
            let declargs = ~[llmdnode(~[llptr]), mdnode];
            trans::build::Call(bcx, cx.intrinsics.get(~"llvm.dbg.declare"),
                               declargs);
            return Some(mdval);
        }
        _ => {
            return None;
        }
    }
739 740
}

741
fn update_source_pos(cx: block, s: span) {
742
    if !cx.sess().opts.debuginfo {
B
Brian Anderson 已提交
743
        return;
744
    }
745
    let cm = cx.sess().codemap;
746
    let blockmd = create_block(cx);
B
Brian Anderson 已提交
747
    let loc = cm.lookup_char_pos(s.lo);
748 749
    let scopedata = ~[lli32(loc.line.to_int()),
                     lli32(loc.col.to_int()),
750
                     blockmd.node,
751
                     llnull()];
752
    let dbgscope = llmdnode(scopedata);
753 754 755
    unsafe {
        llvm::LLVMSetCurrentDebugLocation(trans::build::B(cx), dbgscope);
    }
756 757
}

758
fn create_function(fcx: fn_ctxt) -> @metadata<subprogram_md> {
759
    let cx = fcx.ccx;
760
    let dbg_cx = (/*bad*/copy cx.dbg_cx).get();
761

P
Paul Stansifer 已提交
762
    debug!("~~");
763
    log(debug, fcx.id);
764

B
Brian Anderson 已提交
765
    let sp = fcx.span.get();
B
Brian Anderson 已提交
766
    log(debug, cx.sess.codemap.span_to_str(sp));
767

768
    let (ident, ret_ty, id) = match cx.tcx.items.get(fcx.id) {
B
Brian Anderson 已提交
769
      ast_map::node_item(item, _) => {
770
        match /*bad*/copy item.node {
771
          ast::item_fn(decl, _, _, _) => {
772
            (item.ident, decl.output, item.id)
773
          }
B
Brian Anderson 已提交
774 775
          _ => fcx.ccx.sess.span_bug(item.span, ~"create_function: item \
                                                  bound to non-function")
776 777
        }
      }
B
Brian Anderson 已提交
778
      ast_map::node_method(method, _, _) => {
779 780
          (method.ident, method.decl.output, method.id)
      }
B
Brian Anderson 已提交
781
      ast_map::node_expr(expr) => {
782
        match /*bad*/copy expr.node {
B
Brian Anderson 已提交
783
          ast::expr_fn(_, decl, _, _) => {
784
            ((dbg_cx.names)(~"fn"), decl.output, expr.id)
785
          }
B
Brian Anderson 已提交
786
          ast::expr_fn_block(decl, _, _) => {
787
            ((dbg_cx.names)(~"fn"), decl.output, expr.id)
788
          }
B
Brian Anderson 已提交
789 790 791
          _ => fcx.ccx.sess.span_bug(expr.span,
                                     ~"create_function: \
                                       expected an expr_fn or fn_block here")
792 793
        }
      }
B
Brian Anderson 已提交
794 795
      _ => fcx.ccx.sess.bug(~"create_function: unexpected \
                              sort of node")
796
    };
797

798 799
    log(debug, ident);
    log(debug, id);
800

801
    let cache = get_cache(cx);
802
    match cached_metadata::<@metadata<subprogram_md>>(
B
Brian Anderson 已提交
803
        cache, SubprogramTag, |md| md.data.id == id) {
B
Brian Anderson 已提交
804 805
      option::Some(md) => return md,
      option::None => ()
806
    }
807

B
Brian Anderson 已提交
808
    let loc = cx.sess.codemap.lookup_char_pos(sp.lo);
809
    let file_node = create_file(cx, loc.file.name).node;
810
    let ty_node = if cx.sess.opts.extra_debuginfo {
811
        match ret_ty.node {
B
Brian Anderson 已提交
812 813
          ast::ty_nil => llnull(),
          _ => create_ty(cx, ty::node_id_to_type(cx.tcx, id), ret_ty).node
814 815 816
        }
    } else {
        llnull()
817
    };
818
    let sub_node = create_composite_type(SubroutineTag, ~"", file_node, 0, 0,
B
Brian Anderson 已提交
819 820
                                         0, 0, option::None,
                                         option::Some(~[ty_node]));
821

822
    let fn_metadata = ~[lltag(SubprogramTag),
823 824
                       llunused(),
                       file_node,
P
Paul Stansifer 已提交
825 826 827
                       llstr(cx.sess.str_of(ident)),
                        //XXX fully-qualified C++ name:
                       llstr(cx.sess.str_of(ident)),
828
                       llstr(~""), //XXX MIPS name?????
829 830
                       file_node,
                       lli32(loc.line as int),
831
                       sub_node,
832
                       lli1(false), //XXX static (check export)
833
                       lli1(true), // defined in compilation unit
834 835
                       lli32(DW_VIRTUALITY_none), // virtual-ness
                       lli32(0i), //index into virt func
836 837
                       /*llnull()*/ lli32(0), // base type with vtbl
                       lli32(256), // flags
838
                       lli1(cx.sess.opts.optimize != session::No),
839
                       fcx.llfn
840 841 842
                       //list of template params
                       //func decl descriptor
                       //list of func vars
843
                      ];
844
    let val = llmdnode(fn_metadata);
845
    add_named_metadata(cx, ~"llvm.dbg.sp", val);
846
    let mdval = @{node: val, data: {id: id}};
847
    update_cache(cache, SubprogramTag, subprogram_metadata(mdval));
848

B
Brian Anderson 已提交
849
    return mdval;
J
Josh Matthews 已提交
850
}