Generate basic debug info for files, functions and compile units.
This commit is contained in:
parent
fa27724a4b
commit
10030a37d5
7 changed files with 222 additions and 3 deletions
|
@ -256,6 +256,7 @@ native mod llvm {
|
||||||
|
|
||||||
/* Operations on Users */
|
/* Operations on Users */
|
||||||
fn LLVMGetOperand(Val: ValueRef, Index: uint) -> ValueRef;
|
fn LLVMGetOperand(Val: ValueRef, Index: uint) -> ValueRef;
|
||||||
|
fn LLVMSetOperand(Val: ValueRef, Index: uint, Op: ValueRef);
|
||||||
|
|
||||||
/* Operations on constants of any type */
|
/* Operations on constants of any type */
|
||||||
fn LLVMConstNull(Ty: TypeRef) -> ValueRef;
|
fn LLVMConstNull(Ty: TypeRef) -> ValueRef;
|
||||||
|
@ -275,6 +276,8 @@ native mod llvm {
|
||||||
fn LLVMMDNodeInContext(C: ContextRef, Vals: *ValueRef, Count: uint) ->
|
fn LLVMMDNodeInContext(C: ContextRef, Vals: *ValueRef, Count: uint) ->
|
||||||
ValueRef;
|
ValueRef;
|
||||||
fn LLVMMDNode(Vals: *ValueRef, Count: uint) -> ValueRef;
|
fn LLVMMDNode(Vals: *ValueRef, Count: uint) -> ValueRef;
|
||||||
|
fn LLVMAddNamedMetadataOperand(M: ModuleRef, Str: sbuf, SLen: uint,
|
||||||
|
Val: ValueRef);
|
||||||
|
|
||||||
/* Operations on scalar constants */
|
/* Operations on scalar constants */
|
||||||
fn LLVMConstInt(IntTy: TypeRef, N: ULongLong, SignExtend: Bool) ->
|
fn LLVMConstInt(IntTy: TypeRef, N: ULongLong, SignExtend: Bool) ->
|
||||||
|
|
192
src/comp/middle/debuginfo.rs
Normal file
192
src/comp/middle/debuginfo.rs
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
import std::{vec, str, map, option, unsafe};
|
||||||
|
import std::vec::to_ptr;
|
||||||
|
import std::map::hashmap;
|
||||||
|
import lib::llvm::llvm;
|
||||||
|
import lib::llvm::llvm::{ModuleRef, ValueRef};
|
||||||
|
import middle::trans_common::*;
|
||||||
|
import syntax::{ast, codemap};
|
||||||
|
|
||||||
|
const LLVMDebugVersion: int = 0x80000;
|
||||||
|
|
||||||
|
const DW_LANG_RUST: int = 0x9000;
|
||||||
|
const DW_VIRTUALITY_none: int = 0;
|
||||||
|
|
||||||
|
const CompileUnitTag: int = 17;
|
||||||
|
const FileDescriptorTag: int = 41;
|
||||||
|
const SubprogramTag: int = 46;
|
||||||
|
|
||||||
|
fn as_buf(s: str) -> str::sbuf {
|
||||||
|
str::as_buf(s, {|sbuf| sbuf})
|
||||||
|
}
|
||||||
|
fn llstr(s: str) -> ValueRef {
|
||||||
|
llvm::LLVMMDString(as_buf(s), str::byte_len(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lltag(lltag: int) -> ValueRef {
|
||||||
|
lli32(0x80000 + lltag)
|
||||||
|
}
|
||||||
|
fn lli32(val: int) -> ValueRef {
|
||||||
|
C_i32(val as i32)
|
||||||
|
}
|
||||||
|
fn lli1(bval: bool) -> ValueRef {
|
||||||
|
C_bool(bval)
|
||||||
|
}
|
||||||
|
fn llmdnode(elems: [ValueRef]) -> ValueRef unsafe {
|
||||||
|
llvm::LLVMMDNode(vec::unsafe::to_ptr(elems),
|
||||||
|
vec::len(elems))
|
||||||
|
}
|
||||||
|
fn llunused() -> ValueRef {
|
||||||
|
lli32(0x0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_cache(cache: metadata_cache, mdtag: int, val: debug_metadata) {
|
||||||
|
let existing = if cache.contains_key(mdtag) {
|
||||||
|
cache.get(mdtag)
|
||||||
|
} else {
|
||||||
|
[]
|
||||||
|
};
|
||||||
|
cache.insert(mdtag, existing + [val]);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
type metadata<T> = {node: ValueRef, data: T};
|
||||||
|
|
||||||
|
type file_md = {path: str};
|
||||||
|
type compile_unit_md = {path: str};
|
||||||
|
type subprogram_md = {name: str, file: str};
|
||||||
|
|
||||||
|
type metadata_cache = hashmap<int, [debug_metadata]>;
|
||||||
|
|
||||||
|
tag debug_metadata {
|
||||||
|
file_metadata(@metadata<file_md>);
|
||||||
|
compile_unit_metadata(@metadata<compile_unit_md>);
|
||||||
|
subprogram_metadata(@metadata<subprogram_md>);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn md_from_metadata<T>(val: debug_metadata) -> T unsafe {
|
||||||
|
alt val {
|
||||||
|
file_metadata(md) { unsafe::reinterpret_cast(md) }
|
||||||
|
compile_unit_metadata(md) { unsafe::reinterpret_cast(md) }
|
||||||
|
subprogram_metadata(md) { unsafe::reinterpret_cast(md) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cached_metadata<T>(cache: metadata_cache, mdtag: int,
|
||||||
|
eq: block(md: T) -> bool) -> option::t<T> {
|
||||||
|
if cache.contains_key(mdtag) {
|
||||||
|
let items = cache.get(mdtag);
|
||||||
|
for item in items {
|
||||||
|
let md: T = md_from_metadata::<T>(item);
|
||||||
|
if eq(md) {
|
||||||
|
ret option::some(md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret option::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_compile_unit_metadata(cx: @crate_ctxt, full_path: str)
|
||||||
|
-> @metadata<compile_unit_md> {
|
||||||
|
let cache = cx.llmetadata;
|
||||||
|
alt cached_metadata::<@metadata<compile_unit_md>>(cache, CompileUnitTag,
|
||||||
|
{|md| md.data.path == full_path}) {
|
||||||
|
option::some(md) { ret md; }
|
||||||
|
option::none. {}
|
||||||
|
}
|
||||||
|
let sep = str::rindex(full_path, '/' as u8) as uint;
|
||||||
|
let fname = str::slice(full_path, sep + 1u,
|
||||||
|
str::byte_len(full_path));
|
||||||
|
let path = str::slice(full_path, 0u, sep + 1u);
|
||||||
|
let unit_metadata = [lltag(CompileUnitTag),
|
||||||
|
llunused(),
|
||||||
|
lli32(DW_LANG_RUST),
|
||||||
|
llstr(fname),
|
||||||
|
llstr(path),
|
||||||
|
llstr(#env["CFG_VERSION"]),
|
||||||
|
lli1(false), // main compile unit
|
||||||
|
lli1(cx.sess.get_opts().optimize != 0u),
|
||||||
|
llstr(""), // flags (???)
|
||||||
|
lli32(0) // runtime version (???)
|
||||||
|
// list of enum types
|
||||||
|
// list of retained values
|
||||||
|
// list of subprograms
|
||||||
|
// list of global variables
|
||||||
|
];
|
||||||
|
let unit_node = llmdnode(unit_metadata);
|
||||||
|
llvm::LLVMAddNamedMetadataOperand(cx.llmod, as_buf("llvm.dbg.cu"),
|
||||||
|
str::byte_len("llvm.dbg.cu"),
|
||||||
|
unit_node);
|
||||||
|
let mdval = @{node: unit_node, data: {path: full_path}};
|
||||||
|
update_cache(cache, CompileUnitTag, compile_unit_metadata(mdval));
|
||||||
|
ret mdval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// let kind_id = llvm::LLVMGetMDKindID(as_buf("dbg"),
|
||||||
|
// str::byte_len("dbg"));
|
||||||
|
|
||||||
|
|
||||||
|
fn get_file_metadata(cx: @crate_ctxt, full_path: str) -> @metadata<file_md> {
|
||||||
|
let cache = cx.llmetadata;
|
||||||
|
alt cached_metadata::<@metadata<file_md>>(
|
||||||
|
cache, FileDescriptorTag, {|md| md.data.path == full_path}) {
|
||||||
|
option::some(md) { ret md; }
|
||||||
|
option::none. {}
|
||||||
|
}
|
||||||
|
let sep = str::rindex(full_path, '/' as u8) as uint;
|
||||||
|
let fname = str::slice(full_path, sep + 1u,
|
||||||
|
str::byte_len(full_path));
|
||||||
|
let path = str::slice(full_path, 0u, sep + 1u);
|
||||||
|
let unit_node = get_compile_unit_metadata(cx, path).node;
|
||||||
|
let file_md = [lltag(FileDescriptorTag),
|
||||||
|
llstr(fname),
|
||||||
|
llstr(path),
|
||||||
|
unit_node];
|
||||||
|
let val = llmdnode(file_md);
|
||||||
|
let mdval = @{node: val, data: {path: full_path}};
|
||||||
|
update_cache(cache, FileDescriptorTag, file_metadata(mdval));
|
||||||
|
ret mdval;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_function_metadata(cx: @crate_ctxt, item: @ast::item,
|
||||||
|
llfndecl: ValueRef) -> @metadata<subprogram_md> {
|
||||||
|
let cache = cx.llmetadata;
|
||||||
|
alt cached_metadata::<@metadata<subprogram_md>>(
|
||||||
|
cache, SubprogramTag, {|md| md.data.name == item.ident &&
|
||||||
|
/*sub.path == ??*/ true}) {
|
||||||
|
option::some(md) { ret md; }
|
||||||
|
option::none. {}
|
||||||
|
}
|
||||||
|
let loc = codemap::lookup_char_pos(cx.sess.get_codemap(),
|
||||||
|
item.span.lo);
|
||||||
|
let file_node = get_file_metadata(cx, loc.filename).node;
|
||||||
|
let fn_metadata = [lltag(SubprogramTag),
|
||||||
|
llunused(),
|
||||||
|
file_node,
|
||||||
|
llstr(item.ident),
|
||||||
|
llstr(item.ident), //XXX fully-qualified C++ name
|
||||||
|
llstr(item.ident), //XXX MIPS name?????
|
||||||
|
file_node,
|
||||||
|
lli32(loc.line as int),
|
||||||
|
C_null(T_ptr(T_nil())), // XXX reference to tydesc
|
||||||
|
lli1(false), //XXX static
|
||||||
|
lli1(true), // not extern
|
||||||
|
lli32(DW_VIRTUALITY_none), // virtual-ness
|
||||||
|
lli32(0i), //index into virt func
|
||||||
|
C_null(T_ptr(T_nil())), // base type with vtbl
|
||||||
|
lli1(false), // artificial
|
||||||
|
lli1(cx.sess.get_opts().optimize != 0u),
|
||||||
|
llfndecl
|
||||||
|
//list of template params
|
||||||
|
//func decl descriptor
|
||||||
|
//list of func vars
|
||||||
|
];
|
||||||
|
let val = llmdnode(fn_metadata);
|
||||||
|
llvm::LLVMAddNamedMetadataOperand(cx.llmod, as_buf("llvm.dbg.sp"),
|
||||||
|
str::byte_len("llvm.dbg.sp"),
|
||||||
|
val);
|
||||||
|
let mdval = @{node: val, data: {name: item.ident,
|
||||||
|
file: loc.filename}};
|
||||||
|
update_cache(cache, SubprogramTag, subprogram_metadata(mdval));
|
||||||
|
ret mdval;
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ import std::map::{new_int_hash, new_str_hash};
|
||||||
import option::{some, none};
|
import option::{some, none};
|
||||||
import driver::session;
|
import driver::session;
|
||||||
import front::attr;
|
import front::attr;
|
||||||
import middle::{ty, gc, resolve};
|
import middle::{ty, gc, resolve, debuginfo};
|
||||||
import middle::freevars::*;
|
import middle::freevars::*;
|
||||||
import back::{link, abi, upcall};
|
import back::{link, abi, upcall};
|
||||||
import syntax::{ast, ast_util};
|
import syntax::{ast, ast_util};
|
||||||
|
@ -4543,6 +4543,12 @@ fn trans_fn(cx: @local_ctxt, sp: span, f: ast::_fn, llfndecl: ValueRef,
|
||||||
let do_time = cx.ccx.sess.get_opts().stats;
|
let do_time = cx.ccx.sess.get_opts().stats;
|
||||||
let start = do_time ? time::get_time() : {sec: 0u32, usec: 0u32};
|
let start = do_time ? time::get_time() : {sec: 0u32, usec: 0u32};
|
||||||
trans_closure(cx, sp, f, llfndecl, ty_self, ty_params, id, {|_fcx|});
|
trans_closure(cx, sp, f, llfndecl, ty_self, ty_params, id, {|_fcx|});
|
||||||
|
if cx.ccx.sess.get_opts().debuginfo {
|
||||||
|
let item = alt option::get(cx.ccx.ast_map.find(id)) {
|
||||||
|
ast_map::node_item(item) { item }
|
||||||
|
};
|
||||||
|
debuginfo::get_function_metadata(cx.ccx, item, llfndecl);
|
||||||
|
}
|
||||||
if do_time {
|
if do_time {
|
||||||
let end = time::get_time();
|
let end = time::get_time();
|
||||||
log_fn_time(cx.ccx, str::connect(cx.path, "::"), start, end);
|
log_fn_time(cx.ccx, str::connect(cx.path, "::"), start, end);
|
||||||
|
@ -5659,7 +5665,8 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
||||||
builder: BuilderRef_res(llvm::LLVMCreateBuilder()),
|
builder: BuilderRef_res(llvm::LLVMCreateBuilder()),
|
||||||
shape_cx: shape::mk_ctxt(llmod),
|
shape_cx: shape::mk_ctxt(llmod),
|
||||||
gc_cx: gc::mk_ctxt(),
|
gc_cx: gc::mk_ctxt(),
|
||||||
crate_map: crate_map};
|
crate_map: crate_map,
|
||||||
|
llmetadata: map::new_int_hash()};
|
||||||
let cx = new_local_ctxt(ccx);
|
let cx = new_local_ctxt(ccx);
|
||||||
collect_items(ccx, crate);
|
collect_items(ccx, crate);
|
||||||
collect_tag_ctors(ccx, crate);
|
collect_tag_ctors(ccx, crate);
|
||||||
|
|
|
@ -116,7 +116,8 @@ type crate_ctxt =
|
||||||
builder: BuilderRef_res,
|
builder: BuilderRef_res,
|
||||||
shape_cx: shape::ctxt,
|
shape_cx: shape::ctxt,
|
||||||
gc_cx: gc::ctxt,
|
gc_cx: gc::ctxt,
|
||||||
crate_map: ValueRef};
|
crate_map: ValueRef,
|
||||||
|
llmetadata: debuginfo::metadata_cache};
|
||||||
|
|
||||||
type local_ctxt =
|
type local_ctxt =
|
||||||
{path: [str],
|
{path: [str],
|
||||||
|
|
|
@ -37,6 +37,7 @@ mod middle {
|
||||||
mod freevars;
|
mod freevars;
|
||||||
mod shape;
|
mod shape;
|
||||||
mod gc;
|
mod gc;
|
||||||
|
mod debuginfo;
|
||||||
|
|
||||||
mod tstate {
|
mod tstate {
|
||||||
mod ck;
|
mod ck;
|
||||||
|
|
|
@ -165,3 +165,17 @@ extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M,
|
||||||
return wrap(unwrap(M)->getOrInsertFunction(Name,
|
return wrap(unwrap(M)->getOrInsertFunction(Name,
|
||||||
unwrap<FunctionType>(FunctionTy)));
|
unwrap<FunctionType>(FunctionTy)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) {
|
||||||
|
return wrap(Type::getMetadataTy(*unwrap(C)));
|
||||||
|
}
|
||||||
|
extern "C" LLVMTypeRef LLVMMetadataType(void) {
|
||||||
|
return LLVMMetadataTypeInContext(LLVMGetGlobalContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void LLVMAddNamedMetadataOperand(LLVMModuleRef M, const char *Str,
|
||||||
|
unsigned SLen, LLVMValueRef Val)
|
||||||
|
{
|
||||||
|
NamedMDNode *N = unwrap(M)->getOrInsertNamedMetadata(StringRef(Str, SLen));
|
||||||
|
N->addOperand(unwrap<MDNode>(Val));
|
||||||
|
}
|
||||||
|
|
|
@ -487,6 +487,7 @@ LLVMMDNode
|
||||||
LLVMMDNodeInContext
|
LLVMMDNodeInContext
|
||||||
LLVMMDString
|
LLVMMDString
|
||||||
LLVMMDStringInContext
|
LLVMMDStringInContext
|
||||||
|
LLVMAddNamedMetadataOperand
|
||||||
LLVMModuleCreateWithName
|
LLVMModuleCreateWithName
|
||||||
LLVMModuleCreateWithNameInContext
|
LLVMModuleCreateWithNameInContext
|
||||||
LLVMMoveBasicBlockAfter
|
LLVMMoveBasicBlockAfter
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue