568 lines
20 KiB
Rust
568 lines
20 KiB
Rust
import std::{vec, str, option, unsafe, fs, sys};
|
|
import std::map::hashmap;
|
|
import lib::llvm::llvm;
|
|
import lib::llvm::llvm::ValueRef;
|
|
import middle::trans_common::*;
|
|
import middle::ty;
|
|
import syntax::{ast, codemap};
|
|
import ast::ty;
|
|
|
|
const LLVMDebugVersion: int = (9 << 16);
|
|
|
|
const DW_LANG_RUST: int = 0x9000;
|
|
const DW_VIRTUALITY_none: int = 0;
|
|
|
|
const CompileUnitTag: int = 17;
|
|
const FileDescriptorTag: int = 41;
|
|
const SubprogramTag: int = 46;
|
|
const SubroutineTag: int = 21;
|
|
const BasicTypeDescriptorTag: int = 36;
|
|
const AutoVariableTag: int = 256;
|
|
const ArgVariableTag: int = 257;
|
|
const ReturnVariableTag: int = 258;
|
|
const LexicalBlockTag: int = 11;
|
|
|
|
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;
|
|
|
|
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(LLVMDebugVersion | lltag)
|
|
}
|
|
fn lli32(val: int) -> ValueRef {
|
|
C_i32(val as i32)
|
|
}
|
|
fn lli64(val: int) -> ValueRef {
|
|
C_i64(val as i64)
|
|
}
|
|
fn lli1(bval: bool) -> ValueRef {
|
|
C_bool(bval)
|
|
}
|
|
fn llmdnode(elems: [ValueRef]) -> ValueRef unsafe {
|
|
llvm::LLVMMDNode(vec::unsafe::to_ptr(elems),
|
|
vec::len(elems))
|
|
}
|
|
fn llunused() -> ValueRef {
|
|
lli32(0x0)
|
|
}
|
|
fn llnull() -> ValueRef unsafe {
|
|
unsafe::reinterpret_cast(std::ptr::null::<ValueRef>())
|
|
}
|
|
|
|
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 local_var_md = {id: ast::node_id};
|
|
type tydesc_md = {hash: uint};
|
|
type block_md = {start: codemap::loc, end: codemap::loc};
|
|
type argument_md = {id: ast::node_id};
|
|
type retval_md = {id: ast::node_id};
|
|
|
|
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>);
|
|
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>);
|
|
}
|
|
|
|
fn cast_safely<copy T, U>(val: T) -> U unsafe {
|
|
let val2 = val;
|
|
let val3 = unsafe::reinterpret_cast(val2);
|
|
unsafe::leak(val2);
|
|
ret val3;
|
|
}
|
|
|
|
fn md_from_metadata<T>(val: debug_metadata) -> T unsafe {
|
|
alt val {
|
|
file_metadata(md) { cast_safely(md) }
|
|
compile_unit_metadata(md) { cast_safely(md) }
|
|
subprogram_metadata(md) { cast_safely(md) }
|
|
local_var_metadata(md) { cast_safely(md) }
|
|
tydesc_metadata(md) { cast_safely(md) }
|
|
block_metadata(md) { cast_safely(md) }
|
|
argument_metadata(md) { cast_safely(md) }
|
|
retval_metadata(md) { cast_safely(md) }
|
|
}
|
|
}
|
|
|
|
fn cached_metadata<copy T>(cache: metadata_cache, mdtag: int,
|
|
eq: block(md: T) -> bool) -> option::t<T> unsafe {
|
|
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 fname = fs::basename(full_path);
|
|
let path = fs::dirname(full_path);
|
|
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;
|
|
}
|
|
|
|
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 fname = fs::basename(full_path);
|
|
let path = fs::dirname(full_path);
|
|
let unit_node = get_compile_unit_metadata(cx, full_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_block_metadata(cx: @block_ctxt) -> @metadata<block_md> {
|
|
let cache = bcx_ccx(cx).llmetadata;
|
|
let start = codemap::lookup_char_pos(bcx_ccx(cx).sess.get_codemap(),
|
|
cx.sp.lo);
|
|
let fname = start.filename;
|
|
let end = codemap::lookup_char_pos(bcx_ccx(cx).sess.get_codemap(),
|
|
cx.sp.hi);
|
|
alt cached_metadata::<@metadata<block_md>>(
|
|
cache, LexicalBlockTag,
|
|
{|md| start == md.data.start && end == md.data.end}) {
|
|
option::some(md) { ret md; }
|
|
option::none. {}
|
|
}
|
|
let parent = alt cx.parent {
|
|
trans_common::parent_none. { function_metadata_from_block(cx).node }
|
|
trans_common::parent_some(bcx) { get_block_metadata(cx).node }
|
|
};
|
|
let file_node = get_file_metadata(bcx_ccx(cx), fname);
|
|
let unique_id = alt cache.find(LexicalBlockTag) {
|
|
option::some(v) { vec::len(v) as int }
|
|
option::none. { 0 }
|
|
};
|
|
let lldata = [lltag(LexicalBlockTag),
|
|
parent,
|
|
lli32(start.line as int),
|
|
lli32(start.col as int),
|
|
file_node.node,
|
|
lli32(unique_id)
|
|
];
|
|
let val = llmdnode(lldata);
|
|
let mdval = @{node: val, data: {start: start, end: end}};
|
|
update_cache(cache, LexicalBlockTag, block_metadata(mdval));
|
|
ret mdval;
|
|
}
|
|
|
|
fn get_ty_metadata(cx: @crate_ctxt, t: ty::t, ty: @ast::ty) -> @metadata<tydesc_md> {
|
|
let cache = cx.llmetadata;
|
|
alt cached_metadata::<@metadata<tydesc_md>>(
|
|
cache, BasicTypeDescriptorTag,
|
|
{|md| ty::hash_ty(t) == ty::hash_ty(md.data.hash)}) {
|
|
option::some(md) { ret md; }
|
|
option::none. {}
|
|
}
|
|
fn size_and_align_of<T>() -> (int, int) {
|
|
(sys::size_of::<T>() as int, sys::align_of::<T>() as int)
|
|
}
|
|
let ast_ty = alt ty.node {
|
|
ast::ty_infer. {
|
|
alt ty::struct(ccx_tcx(cx), t) {
|
|
ty::ty_bool. { ast::ty_bool }
|
|
ty::ty_int. { ast::ty_int }
|
|
ty::ty_uint. { ast::ty_uint }
|
|
ty::ty_float. { ast::ty_float }
|
|
ty::ty_machine(m) { ast::ty_machine(m) }
|
|
ty::ty_char. { ast::ty_char }
|
|
}
|
|
}
|
|
_ { ty.node }
|
|
};
|
|
let (name, (size, align), encoding) = alt ast_ty {
|
|
ast::ty_bool. {("bool", size_and_align_of::<bool>(), DW_ATE_boolean)}
|
|
ast::ty_int. {("int", size_and_align_of::<int>(), DW_ATE_signed)}
|
|
ast::ty_uint. {("uint", size_and_align_of::<uint>(), DW_ATE_unsigned)}
|
|
ast::ty_float. {("float", size_and_align_of::<float>(), DW_ATE_float)}
|
|
ast::ty_machine(m) { alt m {
|
|
ast::ty_i8. {("i8", size_and_align_of::<i8>(), DW_ATE_signed_char)}
|
|
ast::ty_i16. {("i16", size_and_align_of::<i16>(), DW_ATE_signed)}
|
|
ast::ty_i32. {("i32", size_and_align_of::<i32>(), DW_ATE_signed)}
|
|
ast::ty_i64. {("i64", size_and_align_of::<i64>(), DW_ATE_signed)}
|
|
ast::ty_u8. {("u8", size_and_align_of::<u8>(), DW_ATE_unsigned_char)}
|
|
ast::ty_u16. {("u16", size_and_align_of::<u16>(), DW_ATE_unsigned)}
|
|
ast::ty_u32. {("u32", size_and_align_of::<u32>(), DW_ATE_unsigned)}
|
|
ast::ty_u64. {("u64", size_and_align_of::<u64>(), DW_ATE_unsigned)}
|
|
ast::ty_f32. {("f32", size_and_align_of::<f32>(), DW_ATE_float)}
|
|
ast::ty_f64. {("f64", size_and_align_of::<f64>(), DW_ATE_float)}
|
|
} }
|
|
ast::ty_char. {("char", size_and_align_of::<char>(), DW_ATE_unsigned)}
|
|
};
|
|
let fname = filename_from_span(cx, ty.span);
|
|
let file_node = get_file_metadata(cx, fname);
|
|
let cu_node = get_compile_unit_metadata(cx, fname);
|
|
let lldata = [lltag(BasicTypeDescriptorTag),
|
|
cu_node.node,
|
|
llstr(name),
|
|
file_node.node,
|
|
lli32(0), //XXX source line
|
|
lli64(size * 8), // size in bits
|
|
lli64(align * 8), // alignment in bits
|
|
lli64(0), //XXX offset?
|
|
lli32(0), //XXX flags?
|
|
lli32(encoding)];
|
|
let llnode = llmdnode(lldata);
|
|
let mdval = @{node: llnode, data: {hash: ty::hash_ty(t)}};
|
|
update_cache(cache, BasicTypeDescriptorTag, tydesc_metadata(mdval));
|
|
llvm::LLVMAddNamedMetadataOperand(cx.llmod, as_buf("llvm.dbg.ty"),
|
|
str::byte_len("llvm.dbg.ty"),
|
|
llnode);
|
|
ret mdval;
|
|
}
|
|
|
|
fn function_metadata_from_block(bcx: @block_ctxt) -> @metadata<subprogram_md> {
|
|
let cx = bcx_ccx(bcx);
|
|
let fcx = bcx_fcx(bcx);
|
|
let fn_node = cx.ast_map.get(fcx.id);
|
|
let fn_item = alt fn_node { ast_map::node_item(item) { item } };
|
|
get_function_metadata(fcx, fn_item, fcx.llfn)
|
|
}
|
|
|
|
fn filename_from_span(cx: @crate_ctxt, sp: codemap::span) -> str {
|
|
codemap::lookup_char_pos(cx.sess.get_codemap(), sp.lo).filename
|
|
}
|
|
|
|
fn get_local_var_metadata(bcx: @block_ctxt, local: @ast::local)
|
|
-> @metadata<local_var_md> unsafe {
|
|
let cx = bcx_ccx(bcx);
|
|
let cache = cx.llmetadata;
|
|
alt cached_metadata::<@metadata<local_var_md>>(
|
|
cache, AutoVariableTag, {|md| md.data.id == local.node.id}) {
|
|
option::some(md) { ret md; }
|
|
option::none. {}
|
|
}
|
|
let name = alt local.node.pat.node {
|
|
ast::pat_bind(ident) { ident }
|
|
};
|
|
let loc = codemap::lookup_char_pos(cx.sess.get_codemap(),
|
|
local.span.lo);
|
|
let ty = trans::node_id_type(cx, local.node.id);
|
|
let tymd = get_ty_metadata(cx, ty, local.node.ty);
|
|
let filemd = get_file_metadata(cx, loc.filename);
|
|
let context = alt bcx.parent {
|
|
trans_common::parent_none. { function_metadata_from_block(bcx).node }
|
|
trans_common::parent_some(_) { get_block_metadata(bcx).node }
|
|
};
|
|
let lldata = [lltag(AutoVariableTag),
|
|
context, // context
|
|
llstr(name), // name
|
|
filemd.node,
|
|
lli32(loc.line as int), // line
|
|
tymd.node,
|
|
lli32(0) //XXX flags
|
|
];
|
|
let mdnode = llmdnode(lldata);
|
|
let mdval = @{node: mdnode, data: {id: local.node.id}};
|
|
update_cache(cache, AutoVariableTag, local_var_metadata(mdval));
|
|
let llptr = alt bcx.fcx.lllocals.find(local.node.id) {
|
|
option::some(local_mem(v)) { v }
|
|
option::none. {
|
|
alt bcx.fcx.lllocals.get(local.node.pat.id) {
|
|
local_imm(v) { v }
|
|
}
|
|
}
|
|
};
|
|
let declargs = [llmdnode([llptr]), mdnode];
|
|
trans_build::Call(bcx, cx.intrinsics.get("llvm.dbg.declare"),
|
|
declargs);
|
|
ret mdval;
|
|
}
|
|
|
|
//FIXME: consolidate with get_local_var_metadata
|
|
/*fn get_retval_metadata(bcx: @block_ctxt)
|
|
-> @metadata<retval_md> unsafe {
|
|
let fcx = bcx_fcx(bcx);
|
|
let cx = fcx_ccx(fcx);
|
|
let cache = cx.llmetadata;
|
|
alt cached_metadata::<@metadata<retval_md>>(
|
|
cache, ReturnVariableTag, {|md| md.data.id == fcx.id}) {
|
|
option::some(md) { ret md; }
|
|
option::none. {}
|
|
}
|
|
let item = alt option::get(cx.ast_map.find(fcx.id)) {
|
|
ast_map::node_item(item) { item }
|
|
};
|
|
let loc = codemap::lookup_char_pos(cx.sess.get_codemap(),
|
|
fcx.sp.lo);
|
|
let ret_ty = alt item.node {
|
|
ast::item_fn(f, _) { f.decl.output }
|
|
};
|
|
let ty_node = alt ret_ty.node {
|
|
ast::ty_nil. { llnull() }
|
|
_ { get_ty_metadata(cx, ty::node_id_to_type(ccx_tcx(cx), item.id),
|
|
ret_ty).node }
|
|
};
|
|
/*let ty_node = get_ty_metadata(cx, ty::node_id_to_type(ccx_tcx(cx), fcx.id),
|
|
ty).node;*/
|
|
//let ty = trans::node_id_type(cx, arg.id);
|
|
//let tymd = get_ty_metadata(cx, ty, arg.ty);
|
|
let filemd = get_file_metadata(cx, loc.filename);
|
|
let fn_node = cx.ast_map.get(fcx.id);
|
|
let fn_item = alt fn_node { ast_map::node_item(item) { item } };
|
|
let context = get_function_metadata(fcx, fn_item, fcx.llfn);
|
|
let lldata = [lltag(ReturnVariableTag),
|
|
context.node, // context
|
|
llstr("%0"), // name
|
|
filemd.node,
|
|
lli32(loc.line as int), // line
|
|
ty_node,
|
|
lli32(0) //XXX flags
|
|
];
|
|
let mdnode = llmdnode(lldata);
|
|
let mdval = @{node: mdnode, data: {id: fcx.id}};
|
|
update_cache(cache, ReturnVariableTag, retval_metadata(mdval));
|
|
let llptr = fcx.llretptr;
|
|
let declargs = [llmdnode([llptr]), mdnode];
|
|
trans_build::Call(bcx, cx.intrinsics.get("llvm.dbg.declare"),
|
|
declargs);
|
|
ret mdval;
|
|
}*/
|
|
|
|
//FIXME: consolidate with get_local_var_metadata
|
|
fn get_arg_metadata(bcx: @block_ctxt, arg: ast::arg)
|
|
-> @metadata<argument_md> unsafe {
|
|
let fcx = bcx_fcx(bcx);
|
|
let cx = fcx_ccx(fcx);
|
|
let cache = cx.llmetadata;
|
|
alt cached_metadata::<@metadata<argument_md>>(
|
|
cache, ArgVariableTag, {|md| md.data.id == arg.id}) {
|
|
option::some(md) { ret md; }
|
|
option::none. {}
|
|
}
|
|
let arg_n = alt cx.ast_map.get(arg.id) {
|
|
ast_map::node_arg(_, n) { n - 2u }
|
|
};
|
|
let loc = codemap::lookup_char_pos(cx.sess.get_codemap(),
|
|
fcx.sp.lo);
|
|
let ty = trans::node_id_type(cx, arg.id);
|
|
let tymd = get_ty_metadata(cx, ty, arg.ty);
|
|
let filemd = get_file_metadata(cx, loc.filename);
|
|
let fn_node = cx.ast_map.get(fcx.id);
|
|
let fn_item = alt fn_node { ast_map::node_item(item) { item } };
|
|
let context = get_function_metadata(fcx, fn_item, fcx.llfn);
|
|
let lldata = [lltag(ArgVariableTag),
|
|
context.node, // context
|
|
llstr(arg.ident), // name
|
|
filemd.node,
|
|
lli32(loc.line as int), // line
|
|
tymd.node,
|
|
lli32(0) //XXX flags
|
|
];
|
|
let mdnode = llmdnode(lldata);
|
|
let mdval = @{node: mdnode, data: {id: arg.id}};
|
|
update_cache(cache, ArgVariableTag, argument_metadata(mdval));
|
|
let llptr = alt 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);
|
|
ret mdval;
|
|
}
|
|
|
|
fn update_source_pos(cx: @block_ctxt, s: codemap::span) -> @debug_source_pos {
|
|
let dsp = @debug_source_pos(cx);
|
|
if !bcx_ccx(cx).sess.get_opts().debuginfo {
|
|
ret dsp;
|
|
}
|
|
let cm = bcx_ccx(cx).sess.get_codemap();
|
|
if vec::is_empty(cx.source_pos.pos) {
|
|
cx.source_pos.usable = true;
|
|
}
|
|
cx.source_pos.pos += [codemap::lookup_char_pos(cm, s.lo)]; //XXX maybe hi
|
|
ret dsp;
|
|
}
|
|
|
|
fn invalidate_source_pos(cx: @block_ctxt) -> @invalidated_source_pos {
|
|
let isp = @invalidated_source_pos(cx);
|
|
if !bcx_ccx(cx).sess.get_opts().debuginfo {
|
|
ret isp;
|
|
}
|
|
cx.source_pos.usable = false;
|
|
ret isp;
|
|
}
|
|
|
|
fn revalidate_source_pos(cx: @block_ctxt) {
|
|
if !bcx_ccx(cx).sess.get_opts().debuginfo {
|
|
ret;
|
|
}
|
|
cx.source_pos.usable = true;
|
|
}
|
|
|
|
fn reset_source_pos(cx: @block_ctxt) {
|
|
if !bcx_ccx(cx).sess.get_opts().debuginfo {
|
|
ret;
|
|
}
|
|
vec::pop(cx.source_pos.pos);
|
|
}
|
|
|
|
resource debug_source_pos(bcx: @block_ctxt) {
|
|
reset_source_pos(bcx);
|
|
}
|
|
resource invalidated_source_pos(bcx: @block_ctxt) {
|
|
revalidate_source_pos(bcx);
|
|
}
|
|
|
|
fn add_line_info(cx: @block_ctxt, llinstr: ValueRef) {
|
|
if !bcx_ccx(cx).sess.get_opts().debuginfo ||
|
|
!cx.source_pos.usable ||
|
|
vec::is_empty(cx.source_pos.pos) {
|
|
ret;
|
|
}
|
|
let loc = option::get(vec::last(cx.source_pos.pos));
|
|
let blockmd = get_block_metadata(cx);
|
|
let kind_id = llvm::LLVMGetMDKindID(as_buf("dbg"),
|
|
str::byte_len("dbg"));
|
|
let scopedata = [lli32(loc.line as int),
|
|
lli32(loc.col as int),
|
|
blockmd.node,
|
|
llnull()];
|
|
let dbgscope = llmdnode(scopedata);
|
|
llvm::LLVMSetMetadata(llinstr, kind_id, dbgscope);
|
|
}
|
|
|
|
fn get_function_metadata(fcx: @fn_ctxt, item: @ast::item,
|
|
llfndecl: ValueRef) -> @metadata<subprogram_md> {
|
|
let cx = fcx_ccx(fcx);
|
|
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 mangled = cx.item_symbols.get(item.id);
|
|
let ret_ty = alt item.node {
|
|
ast::item_fn(f, _) { f.decl.output }
|
|
};
|
|
let ty_node = alt ret_ty.node {
|
|
ast::ty_nil. { llnull() }
|
|
_ { get_ty_metadata(cx, ty::node_id_to_type(ccx_tcx(cx), item.id),
|
|
ret_ty).node }
|
|
};
|
|
let sub_type = llmdnode([ty_node]);
|
|
let sub_metadata = [lltag(SubroutineTag),
|
|
file_node,
|
|
llstr(""),
|
|
file_node,
|
|
lli32(0),
|
|
lli64(0),
|
|
lli64(0),
|
|
lli64(0),
|
|
lli32(0),
|
|
llnull(),
|
|
sub_type,
|
|
lli32(0),
|
|
llnull()];
|
|
let sub_node = llmdnode(sub_metadata);
|
|
let fn_metadata = [lltag(SubprogramTag),
|
|
llunused(),
|
|
file_node,
|
|
llstr(item.ident),
|
|
llstr(item.ident), //XXX fully-qualified C++ name
|
|
llstr(mangled), //XXX MIPS name?????
|
|
file_node,
|
|
lli32(loc.line as int),
|
|
sub_node,
|
|
lli1(false), //XXX static (check export)
|
|
lli1(true), // not extern
|
|
lli32(DW_VIRTUALITY_none), // virtual-ness
|
|
lli32(0i), //index into virt func
|
|
llnull(), // 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));
|
|
/*alt ret_ty.node {
|
|
ast::ty_nil. {}
|
|
_ { let _ = get_retval_metadata(fcx, ret_ty); }
|
|
}*/
|
|
ret mdval;
|
|
} |