diff --git a/Cargo.lock b/Cargo.lock index eef23132621..c4f89330377 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,6 +22,14 @@ dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arrayvec" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "atty" version = "0.2.11" @@ -284,6 +292,11 @@ dependencies = [ "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fallible-iterator" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -303,6 +316,18 @@ name = "gcc" version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "gimli" +version = "0.16.1" +source = "git+https://github.com/bjorn3/gimli.git?branch=impl_range_write#ff96c190bbb7a41623f009c969cb7ecd7a2716f4" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "fallible-iterator 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "goblin" version = "0.0.19" @@ -375,6 +400,11 @@ dependencies = [ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "plain" version = "0.2.3" @@ -565,6 +595,8 @@ dependencies = [ "cranelift-module 0.26.0 (git+https://github.com/CraneStation/cranelift.git)", "cranelift-simplejit 0.26.0 (git+https://github.com/CraneStation/cranelift.git)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "faerie 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gimli 0.16.1 (git+https://github.com/bjorn3/gimli.git?branch=impl_range_write)", "libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -630,6 +662,11 @@ dependencies = [ "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "stable_deref_trait" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "string-interner" version = "0.6.3" @@ -816,6 +853,7 @@ dependencies = [ "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ar 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "579681b3fecd1e9d6b5ce6969e05f9feb913f296eddaf595be1166a5ca597bc4" +"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5" @@ -843,9 +881,11 @@ dependencies = [ "checksum faerie 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "142ee8f6d2864117a92855815e710b03087763df41ab3c6a97ca25e00e178b98" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum fallible-iterator 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eb7217124812dc5672b7476d0c2d20cfe9f7c0f1ba0904b674a9762a0212f72e" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +"checksum gimli 0.16.1 (git+https://github.com/bjorn3/gimli.git?branch=impl_range_write)" = "" "checksum goblin 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c65cd533b33e3d04c6e393225fa8919ddfcf5862ca8919c7f9a167c312ef41c2" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" @@ -856,6 +896,7 @@ dependencies = [ "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" "checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum proc-macro2 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)" = "d3797b7142c9aa74954e351fc089bbee7958cebbff6bf2815e7ffff0b19f547d" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" @@ -885,6 +926,7 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" "checksum serde_json 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "574378d957d6dcdf1bbb5d562a15cbd5e644159432f84634b94e485267abbcc7" +"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum string-interner 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abb38a0d8fe673c40b10b6b75abcb076a958cc10fb894f14993d9737c4c87000" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad348dc73012fcf78c71f06f9d942232cdd4c859d4b6975e27836c3efc0c3" diff --git a/Cargo.toml b/Cargo.toml index be43b837608..30824626feb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,10 +23,12 @@ target-lexicon = "0.2.0" #goblin = "0.0.17" ar = "0.6.1" bitflags = "1.0.3" -byteorder = "1.2.6" +byteorder = "1.2.7" libc = "0.2.45" tempfile = "3.0.4" env_logger = "0.6" +gimli = { git = "https://github.com/gimli-rs/gimli.git" } +faerie = "0.7.1" # Uncomment to use local checkout of cranelift #[patch."https://github.com/CraneStation/cranelift.git"] @@ -35,5 +37,8 @@ env_logger = "0.6" #cranelift-simplejit = { path = "../cranelift/lib/simplejit" } #cranelift-faerie = { path = "../cranelift/lib/faerie" } +[patch."https://github.com/gimli-rs/gimli.git"] +gimli = { git = "https://github.com/bjorn3/gimli.git", branch = "impl_range_write" } + [profile.dev.overrides."*"] opt-level = 3 diff --git a/abc.cpp b/abc.cpp new file mode 100644 index 00000000000..7f131fdd8fd --- /dev/null +++ b/abc.cpp @@ -0,0 +1,35 @@ +// compile using g++ -std=c++11 -g -c abc.cpp -o abc.o + +struct Opaque; + +struct MyType { + unsigned int field_a; + int field_b; + void* field_c; + float field_d; + //double field_e; + //long long field_f; + bool field_g; + char field_h; + Opaque* field_i; +}; + +MyType bcd(int x, MyType a) { + MyType b = a; + MyType c = b; + MyType d = c; + MyType e = d; + MyType f = e; + MyType g = f; + MyType h = g; + MyType i = h; + MyType j = i; + MyType k = j; + MyType l = k; + MyType m = l; + return b; +} +int main() { + bcd(42, {}); + return 0; +} diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs index c4140ceaf1e..638db7d24ef 100644 --- a/example/mini_core_hello_world.rs +++ b/example/mini_core_hello_world.rs @@ -115,7 +115,18 @@ struct Unique { impl CoerceUnsized> for Unique where T: Unsize {} +fn take_f32(f: f32) {} +fn take_unique(u: Unique<()>) {} + fn main() { + take_unique(Unique { + pointer: 0 as *const (), + _marker: PhantomData, + }); + take_f32(0.1); + + //return; + unsafe { let hello: &[u8] = b"Hello\0" as &[u8; 6]; let ptr: *const u8 = hello as *const [u8] as *const u8; diff --git a/mini_core_hello_world b/mini_core_hello_world new file mode 100755 index 00000000000..f7f7af4b144 Binary files /dev/null and b/mini_core_hello_world differ diff --git a/src/base.rs b/src/base.rs index f780a86515a..698a31312fc 100644 --- a/src/base.rs +++ b/src/base.rs @@ -69,6 +69,13 @@ fn trans_fn<'a, 'clif, 'tcx: 'a, B: Backend + 'static>( let func_id = cx.module .declare_function(&name, linkage, &sig) .unwrap(); + let mut debug_context = cx.debug_context.as_mut().map(|debug_context| FunctionDebugContext::new( + tcx, + debug_context, + mir, + &name, + &sig, + )); // Step 3. Make FunctionBuilder let mut func = Function::with_name_signature(ExternalName::user(0, 0), sig); @@ -101,6 +108,7 @@ fn trans_fn<'a, 'clif, 'tcx: 'a, B: Backend + 'static>( clif_comments, constants: &mut cx.ccx, caches: &mut cx.caches, + spans: Vec::new(), }; // Step 6. Codegen function @@ -108,6 +116,7 @@ fn trans_fn<'a, 'clif, 'tcx: 'a, B: Backend + 'static>( crate::abi::codegen_fn_prelude(&mut fx, start_ebb); codegen_fn_content(&mut fx); }); + let spans = fx.spans.clone(); // Step 7. Write function to file for debugging #[cfg(debug_assertions)] @@ -119,8 +128,12 @@ fn trans_fn<'a, 'clif, 'tcx: 'a, B: Backend + 'static>( // Step 9. Define function cx.caches.context.func = func; cx.module - .define_function(func_id, &mut cx.caches.context) + .define_function_peek_compiled(func_id, &mut cx.caches.context, |size, context, isa| { + debug_context.as_mut().map(|x| x.define(tcx, size, context, isa, &spans[..])); + }) .unwrap(); + //let module = &mut cx.module; + //let caches = &cx.caches; cx.caches.context.clear(); } @@ -154,6 +167,7 @@ fn codegen_fn_content<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx, impl Backend>) fx.bcx.ins().nop(); for stmt in &bb_data.statements { + fx.set_debug_loc(stmt.source_info); trans_stmt(fx, ebb, stmt); } @@ -169,6 +183,8 @@ fn codegen_fn_content<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx, impl Backend>) fx.add_comment(inst, terminator_head); } + fx.set_debug_loc(bb_data.terminator().source_info); + match &bb_data.terminator().kind { TerminatorKind::Goto { target } => { let ebb = fx.get_ebb(*target); @@ -322,6 +338,8 @@ fn trans_stmt<'a, 'tcx: 'a>( ) { let _print_guard = PrintOnPanic(|| format!("stmt {:?}", stmt)); + fx.set_debug_loc(stmt.source_info); + #[cfg(debug_assertions)] match &stmt.kind { StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful diff --git a/src/common.rs b/src/common.rs index d5e07be302c..ded45af6d5e 100644 --- a/src/common.rs +++ b/src/common.rs @@ -539,6 +539,7 @@ pub struct FunctionCx<'a, 'tcx: 'a, B: Backend> { pub clif_comments: crate::pretty_clif::CommentWriter, pub constants: &'a mut crate::constant::ConstantCx, pub caches: &'a mut Caches<'tcx>, + pub spans: Vec, } impl<'a, 'tcx: 'a, B: Backend + 'a> fmt::Debug for FunctionCx<'a, 'tcx, B> { @@ -617,4 +618,11 @@ impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> { pub fn get_local_place(&mut self, local: Local) -> CPlace<'tcx> { *self.local_map.get(&local).unwrap() } + + pub fn set_debug_loc(&mut self, source_info: mir::SourceInfo) { + // FIXME: record scope too + let index = self.spans.len() as u32; + self.spans.push(source_info.span); + self.bcx.set_srcloc(SourceLoc::new(index)); + } } diff --git a/src/debuginfo.rs b/src/debuginfo.rs new file mode 100644 index 00000000000..f4744f6b7be --- /dev/null +++ b/src/debuginfo.rs @@ -0,0 +1,529 @@ +extern crate gimli; + +use crate::prelude::*; + +use std::marker::PhantomData; + +use gimli::write::{ + Address, AttributeValue, CompilationUnit, DebugAbbrev, DebugInfo, DebugLine, DebugRanges, + DebugRngLists, DebugStr, EndianVec, LineProgram, LineProgramId, LineProgramTable, Range, + RangeList, RangesTable, Result, SectionId, StringTable, UnitEntryId, UnitId, UnitTable, Writer, +}; +use gimli::Format; + +// FIXME: use target endian +use byteorder::ByteOrder; +use gimli::RunTimeEndian; + +use faerie::*; + +fn target_endian(tcx: TyCtxt) -> RunTimeEndian { + use rustc::ty::layout::Endian; + + match tcx.data_layout.endian { + Endian::Big => RunTimeEndian::Big, + Endian::Little => RunTimeEndian::Little, + } +} +struct DebugReloc { + offset: u32, + size: u8, + name: String, + addend: i64, +} + +pub struct DebugContext<'tcx> { + endian: RunTimeEndian, + format: Format, + version: u16, + address_size: u8, + + strings: StringTable, + units: UnitTable, + unit_id: UnitId, + line_programs: LineProgramTable, + global_line_program: LineProgramId, + ranges: RangesTable, + unit_ranges: RangeList, + symbol_names: Vec, + + _dummy: PhantomData<&'tcx ()>, +} + +impl<'a, 'tcx: 'a> DebugContext<'tcx> { + pub fn new(tcx: TyCtxt, address_size: u8) -> Self { + // TODO: this should be configurable + let version = 4; + let format = Format::Dwarf32; + + // FIXME: how to get version when building out of tree? + // Normally this would use option_env!("CFG_VERSION"). + let producer = format!("cranelift fn (rustc version {})", "unknown version"); + let comp_dir = tcx.sess.working_dir.0.to_string_lossy().into_owned(); + let name = match tcx.sess.local_crate_source_file { + Some(ref path) => path.to_string_lossy().into_owned(), + None => tcx.crate_name(LOCAL_CRATE).to_string(), + }; + + let mut units = UnitTable::default(); + let mut strings = StringTable::default(); + let mut line_programs = LineProgramTable::default(); + let ranges = RangesTable::default(); + + let global_line_program = line_programs.add(LineProgram::new( + version, + address_size, + format, + 1, + 1, + -5, + 14, + comp_dir.as_bytes(), + name.as_bytes(), + None, + )); + + let unit_id = units.add(CompilationUnit::new(version, address_size, format)); + { + let name = strings.add(&*name); + let comp_dir = strings.add(&*comp_dir); + + let unit = units.get_mut(unit_id); + let root = unit.root(); + let root = unit.get_mut(root); + root.set( + gimli::DW_AT_producer, + AttributeValue::StringRef(strings.add(producer)), + ); + root.set( + gimli::DW_AT_language, + AttributeValue::Language(gimli::DW_LANG_Rust), + ); + root.set(gimli::DW_AT_name, AttributeValue::StringRef(name)); + root.set(gimli::DW_AT_comp_dir, AttributeValue::StringRef(comp_dir)); + root.set( + gimli::DW_AT_stmt_list, + AttributeValue::LineProgramRef(global_line_program), + ); + root.set( + gimli::DW_AT_low_pc, + AttributeValue::Address(Address::Absolute(0)), + ); + } + + DebugContext { + endian: target_endian(tcx), + format, + version, + address_size, + + strings, + units, + unit_id, + line_programs, + global_line_program, + ranges, + unit_ranges: RangeList(Vec::new()), + symbol_names: Vec::new(), + _dummy: PhantomData, + } + } + + fn emit_location(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, entry_id: UnitEntryId, span: Span) { + let loc = tcx.sess.source_map().lookup_char_pos(span.lo()); + + let unit = self.units.get_mut(self.unit_id); + let entry = unit.get_mut(entry_id); + + let file_id = self.strings.add(loc.file.name.to_string()); + entry.set(gimli::DW_AT_decl_file, AttributeValue::StringRef(file_id)); + entry.set( + gimli::DW_AT_decl_line, + AttributeValue::Udata(loc.line as u64), + ); + // FIXME: probably omit this + entry.set( + gimli::DW_AT_decl_column, + AttributeValue::Udata(loc.col.to_usize() as u64), + ); + } + + pub fn emit(&mut self, artifact: &mut Artifact) { + let unit_range_id = self.ranges.add(self.unit_ranges.clone()); + let unit = self.units.get_mut(self.unit_id); + let root = unit.root(); + let root = unit.get_mut(root); + root.set( + gimli::DW_AT_ranges, + AttributeValue::RangeListsRef(unit_range_id), + ); + + let mut debug_abbrev = DebugAbbrev::from(WriterRelocate::new(self)); + let mut debug_info = DebugInfo::from(WriterRelocate::new(self)); + let mut debug_str = DebugStr::from(WriterRelocate::new(self)); + let mut debug_line = DebugLine::from(WriterRelocate::new(self)); + let mut debug_ranges = DebugRanges::from(WriterRelocate::new(self)); + let mut debug_rnglists = DebugRngLists::from(WriterRelocate::new(self)); + + let debug_line_offsets = self.line_programs.write(&mut debug_line).unwrap(); + let debug_str_offsets = self.strings.write(&mut debug_str).unwrap(); + let (debug_ranges_offsets, debug_rnglists_offsets) = self + .ranges + .write( + &mut debug_ranges, + &mut debug_rnglists, + self.format, + self.version, + self.address_size, + ) + .unwrap(); + self.units + .write( + &mut debug_abbrev, + &mut debug_info, + &debug_line_offsets, + &debug_ranges_offsets, + &debug_rnglists_offsets, + &debug_str_offsets, + ) + .unwrap(); + + artifact + .declare_with( + SectionId::DebugAbbrev.name(), + Decl::DebugSection, + debug_abbrev.0.writer.into_vec(), + ) + .unwrap(); + artifact + .declare_with( + SectionId::DebugInfo.name(), + Decl::DebugSection, + debug_info.0.writer.into_vec(), + ) + .unwrap(); + artifact + .declare_with( + SectionId::DebugStr.name(), + Decl::DebugSection, + debug_str.0.writer.into_vec(), + ) + .unwrap(); + artifact + .declare_with( + SectionId::DebugLine.name(), + Decl::DebugSection, + debug_line.0.writer.into_vec(), + ) + .unwrap(); + artifact + .declare_with( + SectionId::DebugRanges.name(), + Decl::DebugSection, + debug_ranges.0.writer.into_vec(), + ) + .unwrap(); + artifact + .declare_with( + SectionId::DebugRngLists.name(), + Decl::DebugSection, + debug_rnglists.0.writer.into_vec(), + ) + .unwrap(); + + for reloc in debug_abbrev.0.relocs { + artifact + .link_with( + faerie::Link { + from: SectionId::DebugAbbrev.name(), + to: &reloc.name, + at: u64::from(reloc.offset), + }, + faerie::Reloc::Debug { + size: reloc.size, + addend: reloc.addend as i32, + }, + ) + .expect("faerie relocation error"); + } + + for reloc in debug_info.0.relocs { + artifact + .link_with( + faerie::Link { + from: SectionId::DebugInfo.name(), + to: &reloc.name, + at: u64::from(reloc.offset), + }, + faerie::Reloc::Debug { + size: reloc.size, + addend: reloc.addend as i32, + }, + ) + .expect("faerie relocation error"); + } + + for reloc in debug_str.0.relocs { + artifact + .link_with( + faerie::Link { + from: SectionId::DebugStr.name(), + to: &reloc.name, + at: u64::from(reloc.offset), + }, + faerie::Reloc::Debug { + size: reloc.size, + addend: reloc.addend as i32, + }, + ) + .expect("faerie relocation error"); + } + + for reloc in debug_line.0.relocs { + artifact + .link_with( + faerie::Link { + from: SectionId::DebugLine.name(), + to: &reloc.name, + at: u64::from(reloc.offset), + }, + faerie::Reloc::Debug { + size: reloc.size, + addend: reloc.addend as i32, + }, + ) + .expect("faerie relocation error"); + } + + for reloc in debug_ranges.0.relocs { + artifact + .link_with( + faerie::Link { + from: SectionId::DebugRanges.name(), + to: &reloc.name, + at: u64::from(reloc.offset), + }, + faerie::Reloc::Debug { + size: reloc.size, + addend: reloc.addend as i32, + }, + ) + .expect("faerie relocation error"); + } + + for reloc in debug_rnglists.0.relocs { + artifact + .link_with( + faerie::Link { + from: SectionId::DebugRngLists.name(), + to: &reloc.name, + at: u64::from(reloc.offset), + }, + faerie::Reloc::Debug { + size: reloc.size, + addend: reloc.addend as i32, + }, + ) + .expect("faerie relocation error"); + } + } + + fn section_name(&self, id: SectionId) -> String { + id.name().to_string() + } +} + +pub struct FunctionDebugContext<'a, 'tcx> { + debug_context: &'a mut DebugContext<'tcx>, + entry_id: UnitEntryId, + symbol: usize, +} + +impl<'a, 'b, 'tcx: 'b> FunctionDebugContext<'a, 'tcx> { + pub fn new( + tcx: TyCtxt<'b, 'tcx, 'tcx>, + debug_context: &'a mut DebugContext<'tcx>, + mir: &Mir, + name: &str, + _sig: &Signature, + ) -> Self { + let symbol = debug_context.symbol_names.len(); + debug_context.symbol_names.push(name.to_string()); + + let unit = debug_context.units.get_mut(debug_context.unit_id); + // FIXME: add to appropriate scope intead of root + let scope = unit.root(); + + let entry_id = unit.add(scope, gimli::DW_TAG_subprogram); + let entry = unit.get_mut(entry_id); + let name_id = debug_context.strings.add(name); + entry.set( + gimli::DW_AT_linkage_name, + AttributeValue::StringRef(name_id), + ); + + entry.set( + gimli::DW_AT_low_pc, + AttributeValue::Address(Address::Relative { symbol, addend: 0 }), + ); + + debug_context.emit_location(tcx, entry_id, mir.span); + + FunctionDebugContext { + debug_context, + entry_id, + symbol, + } + } + + pub fn define( + &mut self, + tcx: TyCtxt, + //module: &mut Module, + size: u32, + context: &Context, + isa: &cranelift::codegen::isa::TargetIsa, + spans: &[Span], + ) { + let unit = self.debug_context.units.get_mut(self.debug_context.unit_id); + // FIXME: add to appropriate scope intead of root + let entry = unit.get_mut(self.entry_id); + let mut size_array = [0; 8]; + byteorder::LittleEndian::write_u64(&mut size_array, size as u64); + entry.set(gimli::DW_AT_high_pc, AttributeValue::Data8(size_array)); + + self.debug_context.unit_ranges.0.push(Range { + begin: Address::Relative { + symbol: self.symbol, + addend: 0, + }, + end: Address::Relative { + symbol: self.symbol, + addend: size as i64, + }, + }); + + let line_program = self + .debug_context + .line_programs + .get_mut(self.debug_context.global_line_program); + + line_program.begin_sequence(Some(Address::Relative { + symbol: self.symbol, + addend: 0, + })); + + let encinfo = isa.encoding_info(); + let func = &context.func; + let mut ebbs = func.layout.ebbs().collect::>(); + ebbs.sort_by_key(|ebb| func.offsets[*ebb]); // Ensure inst offsets always increase + for ebb in ebbs { + for (offset, inst, _size) in func.inst_offsets(ebb, &encinfo) { + let srcloc = func.srclocs[inst]; + if !srcloc.is_default() { + let span = spans[srcloc.bits() as usize]; + let loc = tcx.sess.source_map().lookup_char_pos(span.lo()); + let file = loc.file.name.to_string(); + let file = ::std::path::Path::new(&file); + let dir_id = line_program + .add_directory(file.parent().unwrap().to_str().unwrap().as_bytes()); + let file_id = line_program.add_file( + file.file_name().unwrap().to_str().unwrap().as_bytes(), + dir_id, + None, + ); + line_program.row().file = file_id; + //tcx.sess + // .warn(&format!("srcloc {} {}:{}:{}", offset, file, loc.line, loc.col.to_usize())); + line_program.row().address_offset = offset as u64; + line_program.row().line = loc.line as u64; + line_program.generate_row(); + } + } + } + + let address_offset = line_program.row().address_offset; + line_program.end_sequence(address_offset); + } +} + +struct WriterRelocate<'a, 'tcx> { + ctx: &'a DebugContext<'tcx>, + relocs: Vec, + writer: EndianVec, +} + +impl<'a, 'tcx> WriterRelocate<'a, 'tcx> { + fn new(ctx: &'a DebugContext<'tcx>) -> Self { + WriterRelocate { + ctx, + relocs: Vec::new(), + writer: EndianVec::new(ctx.endian), + } + } +} + +impl<'a, 'tcx> Writer for WriterRelocate<'a, 'tcx> { + type Endian = RunTimeEndian; + + fn endian(&self) -> Self::Endian { + self.writer.endian() + } + + fn len(&self) -> usize { + self.writer.len() + } + + fn write(&mut self, bytes: &[u8]) -> Result<()> { + self.writer.write(bytes) + } + + fn write_at(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { + self.writer.write_at(offset, bytes) + } + + fn write_address(&mut self, address: Address, size: u8) -> Result<()> { + match address { + Address::Absolute(val) => self.write_word(val, size), + Address::Relative { symbol, addend } => { + let offset = self.len() as u64; + self.relocs.push(DebugReloc { + offset: offset as u32, + size, + name: self.ctx.symbol_names[symbol].clone(), + addend: addend as i64, + }); + self.write_word(0, size) + } + } + } + + fn write_offset(&mut self, val: usize, section: SectionId, size: u8) -> Result<()> { + let offset = self.len() as u32; + let name = self.ctx.section_name(section); + self.relocs.push(DebugReloc { + offset, + size, + name, + addend: val as i64, + }); + self.write_word(0, size) + } + + fn write_offset_at( + &mut self, + offset: usize, + val: usize, + section: SectionId, + size: u8, + ) -> Result<()> { + let name = self.ctx.section_name(section); + self.relocs.push(DebugReloc { + offset: offset as u32, + size, + name, + addend: val as i64, + }); + self.write_word_at(offset, 0, size) + } +} diff --git a/src/lib.rs b/src/lib.rs index 7df9b6ae42e..7b0e4d231d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ use std::sync::mpsc; use rustc::dep_graph::DepGraph; use rustc::middle::cstore::MetadataLoader; use rustc::session::{ - config::{OutputFilenames, OutputType}, + config::{DebugInfo, OutputFilenames, OutputType}, CompileIncomplete, }; use rustc::ty::query::Providers; @@ -43,6 +43,7 @@ mod archive; mod base; mod common; mod constant; +mod debuginfo; mod intrinsics; mod link; mod link_copied; @@ -59,7 +60,7 @@ mod prelude { pub use std::collections::{HashMap, HashSet}; pub use syntax::ast::{FloatTy, IntTy, UintTy}; - pub use syntax::source_map::DUMMY_SP; + pub use syntax::source_map::{DUMMY_SP, Span, Pos}; pub use rustc::bug; pub use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -85,17 +86,21 @@ mod prelude { pub use rustc_codegen_ssa::traits::*; pub use cranelift::codegen::ir::{ - condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, StackSlot, + condcodes::IntCC, function::Function, ExternalName, FuncRef, Inst, StackSlot, SourceLoc, }; pub use cranelift::codegen::isa::CallConv; pub use cranelift::codegen::Context; pub use cranelift::prelude::*; - pub use cranelift_module::{Backend, DataContext, DataId, FuncId, Linkage, Module}; + pub use cranelift_module::{ + self, Backend, DataContext, DataId, FuncId, FuncOrDataId, Linkage, + Module, + }; pub use cranelift_simplejit::{SimpleJITBackend, SimpleJITBuilder}; pub use crate::abi::*; pub use crate::base::{trans_operand, trans_place}; pub use crate::common::*; + pub use crate::debuginfo::{DebugContext, FunctionDebugContext}; pub use crate::trap::*; pub use crate::unimpl::{unimpl, with_unimpl_span}; pub use crate::{Caches, CodegenCx}; @@ -120,15 +125,21 @@ pub struct CodegenCx<'a, 'clif, 'tcx, B: Backend + 'static> { module: &'clif mut Module, ccx: ConstantCx, caches: Caches<'tcx>, + debug_context: Option<&'clif mut DebugContext<'tcx>>, } impl<'a, 'clif, 'tcx, B: Backend + 'static> CodegenCx<'a, 'clif, 'tcx, B> { - fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, module: &'clif mut Module) -> Self { + fn new( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + module: &'clif mut Module, + debug_context: Option<&'clif mut DebugContext<'tcx>>, + ) -> Self { CodegenCx { tcx, module, ccx: ConstantCx::default(), caches: Caches::default(), + debug_context, } } @@ -225,7 +236,7 @@ impl CodegenBackend for CraneliftCodegenBackend { .declare_function("main", Linkage::Import, &sig) .unwrap(); - codegen_cgus(tcx, &mut jit_module, &mut log); + codegen_cgus(tcx, &mut jit_module, &mut None, &mut log); crate::allocator::codegen(tcx.sess, &mut jit_module); jit_module.finalize_definitions(); @@ -261,9 +272,13 @@ impl CodegenBackend for CraneliftCodegenBackend { module }; - let emit_module = |name: &str, kind: ModuleKind, mut module: Module| { + let emit_module = |name: &str, kind: ModuleKind, mut module: Module, debug: Option| { module.finalize_definitions(); - let artifact = module.finish().artifact; + let mut artifact = module.finish().artifact; + + if let Some(mut debug) = debug { + debug.emit(&mut artifact); + } let tmp_file = tcx .output_filenames(LOCAL_CRATE) @@ -281,7 +296,14 @@ impl CodegenBackend for CraneliftCodegenBackend { let mut faerie_module = new_module("some_file".to_string()); - codegen_cgus(tcx, &mut faerie_module, &mut log); + let mut debug = if tcx.sess.opts.debuginfo != DebugInfo::None { + let debug = DebugContext::new(tcx, faerie_module.target_config().pointer_type().bytes() as u8); + Some(debug) + } else { + None + }; + + codegen_cgus(tcx, &mut faerie_module, &mut debug, &mut log); tcx.sess.abort_if_errors(); @@ -291,9 +313,9 @@ impl CodegenBackend for CraneliftCodegenBackend { return Box::new(CodegenResults { crate_name: tcx.crate_name(LOCAL_CRATE), - modules: vec![emit_module("dummy_name", ModuleKind::Regular, faerie_module)], + modules: vec![emit_module("dummy_name", ModuleKind::Regular, faerie_module, debug)], allocator_module: if created_alloc_shim { - Some(emit_module("allocator_shim", ModuleKind::Allocator, allocator_module)) + Some(emit_module("allocator_shim", ModuleKind::Allocator, allocator_module, None)) } else { None }, @@ -372,6 +394,7 @@ fn build_isa(sess: &Session) -> Box { fn codegen_cgus<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, module: &mut Module, + debug: &mut Option>, log: &mut Option, ) { let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); @@ -382,7 +405,7 @@ fn codegen_cgus<'a, 'tcx: 'a>( .map(|(&mono_item, &(linkage, vis))| (mono_item, (linkage, vis))) .collect::>(); - codegen_mono_items(tcx, module, log, mono_items); + codegen_mono_items(tcx, module, debug.as_mut(), log, mono_items); crate::main_shim::maybe_create_entry_wrapper(tcx, module); } @@ -390,10 +413,11 @@ fn codegen_cgus<'a, 'tcx: 'a>( fn codegen_mono_items<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, module: &mut Module, + debug_context: Option<&mut DebugContext<'tcx>>, log: &mut Option, mono_items: FxHashMap, (RLinkage, Visibility)>, ) { - let mut cx = CodegenCx::new(tcx, module); + let mut cx = CodegenCx::new(tcx, module, debug_context); time("codegen mono items", move || { for (mono_item, (linkage, vis)) in mono_items { unimpl::try_unimpl(tcx, log, || { diff --git a/test.sh b/test.sh index d03b48c96bc..1782df6113d 100755 --- a/test.sh +++ b/test.sh @@ -10,16 +10,16 @@ rm -r target/out || true mkdir -p target/out/clif echo "[BUILD] mini_core" -$RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib +$RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib -g echo "[BUILD] example" -$RUSTC example/example.rs --crate-type lib +$RUSTC example/example.rs --crate-type lib -g echo "[JIT] mini_core_hello_world" SHOULD_RUN=1 $RUSTC --crate-type bin example/mini_core_hello_world.rs --cfg jit echo "[AOT] mini_core_hello_world" -$RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin +$RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g sh -c ./target/out/mini_core_hello_world || true echo "[BUILD] sysroot" @@ -31,7 +31,7 @@ time ./build_sysroot/build_sysroot.sh #./target/out/alloc_example echo "[BUILD] mod_bench" -$RUSTC --sysroot ./build_sysroot/sysroot example/mod_bench.rs --crate-type bin +$RUSTC --sysroot ./build_sysroot/sysroot example/mod_bench.rs --crate-type bin -g echo "[BUILD] sysroot in release mode" ./build_sysroot/build_sysroot.sh --release