2019-11-12 20:52:32 +01:00
mod emit ;
2019-11-12 21:08:08 +01:00
mod line_info ;
2019-01-17 18:07:27 +01:00
2019-11-12 20:52:32 +01:00
use crate ::prelude ::* ;
2019-10-16 21:21:20 +02:00
2019-11-11 21:43:57 +01:00
use cranelift ::codegen ::ir ::{ StackSlots , ValueLoc } ;
use cranelift ::codegen ::isa ::RegUnit ;
2019-01-17 18:07:27 +01:00
use gimli ::write ::{
2019-11-12 21:08:08 +01:00
self , Address , AttributeValue , DwarfUnit , Expression , LineProgram , LineString ,
2019-11-12 21:10:51 +01:00
Location , LocationList , Range , RangeList , UnitEntryId , Writer ,
2019-01-17 18:07:27 +01:00
} ;
2019-11-12 20:52:32 +01:00
use gimli ::{ Encoding , Format , LineEncoding , Register , RunTimeEndian , X86_64 } ;
pub use emit ::{ DebugReloc , DebugRelocName } ;
2019-01-17 18:07:27 +01:00
fn target_endian ( tcx : TyCtxt ) -> RunTimeEndian {
use rustc ::ty ::layout ::Endian ;
match tcx . data_layout . endian {
Endian ::Big = > RunTimeEndian ::Big ,
Endian ::Little = > RunTimeEndian ::Little ,
}
}
2019-01-19 12:07:42 +01:00
2019-01-17 18:07:27 +01:00
pub struct DebugContext < ' tcx > {
2019-11-09 18:40:11 +01:00
tcx : TyCtxt < ' tcx > ,
2019-01-17 18:07:27 +01:00
endian : RunTimeEndian ,
2019-10-19 10:52:56 +02:00
symbols : indexmap ::IndexMap < FuncId , String > ,
2019-01-19 12:18:39 +01:00
2019-02-09 17:15:15 +10:00
dwarf : DwarfUnit ,
2019-01-19 12:00:51 +01:00
unit_range_list : RangeList ,
2019-01-17 18:07:27 +01:00
2019-11-09 18:40:11 +01:00
types : HashMap < Ty < ' tcx > , UnitEntryId > ,
2019-01-17 18:07:27 +01:00
}
2019-06-16 11:13:49 +02:00
impl < ' tcx > DebugContext < ' tcx > {
2019-08-18 16:52:07 +02:00
pub fn new ( tcx : TyCtxt < ' tcx > , address_size : u8 ) -> Self {
2019-01-26 12:37:49 +01:00
let encoding = Encoding {
format : Format ::Dwarf32 ,
// TODO: this should be configurable
// macOS doesn't seem to support DWARF > 3
version : 3 ,
address_size ,
} ;
2019-01-17 18:07:27 +01:00
2019-02-09 17:15:15 +10:00
let mut dwarf = DwarfUnit ::new ( encoding ) ;
2019-01-17 18:07:27 +01:00
// 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 ( ) ,
} ;
2019-02-09 17:15:15 +10:00
let line_program = LineProgram ::new (
2019-01-26 12:37:49 +01:00
encoding ,
2019-02-18 18:32:40 +01:00
LineEncoding ::default ( ) ,
2019-02-09 17:15:15 +10:00
LineString ::new ( comp_dir . as_bytes ( ) , encoding , & mut dwarf . line_strings ) ,
LineString ::new ( name . as_bytes ( ) , encoding , & mut dwarf . line_strings ) ,
2019-01-17 18:07:27 +01:00
None ,
2019-02-09 17:15:15 +10:00
) ;
dwarf . unit . line_program = line_program ;
2019-01-17 18:07:27 +01:00
{
2019-02-09 17:15:15 +10:00
let name = dwarf . strings . add ( & * name ) ;
let comp_dir = dwarf . strings . add ( & * comp_dir ) ;
2019-01-17 18:07:27 +01:00
2019-02-09 17:15:15 +10:00
let root = dwarf . unit . root ( ) ;
let root = dwarf . unit . get_mut ( root ) ;
2019-01-17 18:07:27 +01:00
root . set (
gimli ::DW_AT_producer ,
2019-02-09 17:15:15 +10:00
AttributeValue ::StringRef ( dwarf . strings . add ( producer ) ) ,
2019-01-17 18:07:27 +01:00
) ;
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_low_pc ,
2019-05-04 16:20:43 +02:00
AttributeValue ::Address ( Address ::Constant ( 0 ) ) ,
2019-01-17 18:07:27 +01:00
) ;
}
2019-02-21 15:06:09 +01:00
DebugContext {
2019-11-09 18:40:11 +01:00
tcx ,
2019-01-17 18:07:27 +01:00
endian : target_endian ( tcx ) ,
2019-10-19 10:52:56 +02:00
symbols : indexmap ::IndexMap ::new ( ) ,
2019-01-19 12:18:39 +01:00
2019-02-09 17:15:15 +10:00
dwarf ,
2019-01-19 12:00:51 +01:00
unit_range_list : RangeList ( Vec ::new ( ) ) ,
2019-01-19 12:18:39 +01:00
2019-11-09 18:40:11 +01:00
types : HashMap ::new ( ) ,
2019-01-17 18:07:27 +01:00
}
}
2019-11-09 18:40:11 +01:00
fn dwarf_ty ( & mut self , ty : Ty < ' tcx > ) -> UnitEntryId {
if let Some ( type_id ) = self . types . get ( ty ) {
return * type_id ;
}
let new_entry = | dwarf : & mut DwarfUnit , tag | {
dwarf . unit . add ( dwarf . unit . root ( ) , tag )
} ;
let primtive = | dwarf : & mut DwarfUnit , ate | {
let type_id = new_entry ( dwarf , gimli ::DW_TAG_base_type ) ;
let type_entry = dwarf . unit . get_mut ( type_id ) ;
type_entry . set ( gimli ::DW_AT_encoding , AttributeValue ::Encoding ( ate ) ) ;
type_id
} ;
let type_id = match ty . kind {
ty ::Bool = > primtive ( & mut self . dwarf , gimli ::DW_ATE_boolean ) ,
ty ::Char = > primtive ( & mut self . dwarf , gimli ::DW_ATE_UTF ) ,
ty ::Uint ( _ ) = > primtive ( & mut self . dwarf , gimli ::DW_ATE_unsigned ) ,
ty ::Int ( _ ) = > primtive ( & mut self . dwarf , gimli ::DW_ATE_signed ) ,
ty ::Float ( _ ) = > primtive ( & mut self . dwarf , gimli ::DW_ATE_float ) ,
ty ::Ref ( _ , pointee_ty , mutbl ) | ty ::RawPtr ( ty ::TypeAndMut { ty : pointee_ty , mutbl } ) = > {
let type_id = new_entry ( & mut self . dwarf , gimli ::DW_TAG_pointer_type ) ;
// Ensure that type is inserted before recursing to avoid duplicates
self . types . insert ( ty , type_id ) ;
let pointee = self . dwarf_ty ( pointee_ty ) ;
let type_entry = self . dwarf . unit . get_mut ( type_id ) ;
//type_entry.set(gimli::DW_AT_mutable, AttributeValue::Flag(mutbl == rustc::hir::Mutability::MutMutable));
type_entry . set ( gimli ::DW_AT_type , AttributeValue ::ThisUnitEntryRef ( pointee ) ) ;
type_id
}
_ = > new_entry ( & mut self . dwarf , gimli ::DW_TAG_structure_type ) ,
} ;
let name = format! ( " {} " , ty ) ;
let layout = self . tcx . layout_of ( ParamEnv ::reveal_all ( ) . and ( ty ) ) . unwrap ( ) ;
let type_entry = self . dwarf . unit . get_mut ( type_id ) ;
type_entry . set ( gimli ::DW_AT_name , AttributeValue ::String ( name . into_bytes ( ) ) ) ;
type_entry . set ( gimli ::DW_AT_byte_size , AttributeValue ::Udata ( layout . size . bytes ( ) ) ) ;
self . types . insert ( ty , type_id ) ;
type_id
}
2019-01-17 18:07:27 +01:00
}
pub struct FunctionDebugContext < ' a , ' tcx > {
debug_context : & ' a mut DebugContext < ' tcx > ,
entry_id : UnitEntryId ,
symbol : usize ,
2019-11-11 20:49:20 +01:00
instance : Instance < ' tcx > ,
mir : & ' tcx mir ::Body < ' tcx > ,
2019-01-17 18:07:27 +01:00
}
2019-06-16 11:13:49 +02:00
impl < ' a , ' tcx > FunctionDebugContext < ' a , ' tcx > {
2019-01-17 18:07:27 +01:00
pub fn new (
debug_context : & ' a mut DebugContext < ' tcx > ,
2019-11-11 20:49:20 +01:00
instance : Instance < ' tcx > ,
2019-10-16 21:21:20 +02:00
func_id : FuncId ,
2019-01-17 18:07:27 +01:00
name : & str ,
_sig : & Signature ,
) -> Self {
2019-11-11 20:49:20 +01:00
let mir = debug_context . tcx . instance_mir ( instance . def ) ;
2019-10-19 10:52:56 +02:00
let ( symbol , _ ) = debug_context . symbols . insert_full ( func_id , name . to_string ( ) ) ;
2019-01-17 18:07:27 +01:00
// FIXME: add to appropriate scope intead of root
2019-02-09 17:15:15 +10:00
let scope = debug_context . dwarf . unit . root ( ) ;
2019-01-17 18:07:27 +01:00
2019-02-21 15:06:09 +01:00
let entry_id = debug_context
. dwarf
. unit
. add ( scope , gimli ::DW_TAG_subprogram ) ;
2019-02-09 17:15:15 +10:00
let entry = debug_context . dwarf . unit . get_mut ( entry_id ) ;
let name_id = debug_context . dwarf . strings . add ( name ) ;
2019-01-17 18:07:27 +01:00
entry . set (
gimli ::DW_AT_linkage_name ,
AttributeValue ::StringRef ( name_id ) ,
) ;
FunctionDebugContext {
debug_context ,
entry_id ,
symbol ,
2019-11-11 20:49:20 +01:00
instance ,
mir ,
2019-01-17 18:07:27 +01:00
}
}
2019-11-12 20:43:34 +01:00
fn define_local ( & mut self , local : mir ::Local ) -> UnitEntryId {
let local_decl = & self . mir . local_decls [ local ] ;
let ty = self . debug_context . tcx . subst_and_normalize_erasing_regions (
self . instance . substs ,
ty ::ParamEnv ::reveal_all ( ) ,
& local_decl . ty ,
) ;
let dw_ty = self . debug_context . dwarf_ty ( ty ) ;
let name = if let Some ( name ) = local_decl . name {
format! ( " {} {:?} " , name . as_str ( ) , local )
} else {
format! ( " {:?} " , local )
} ;
let var_id = self
. debug_context
. dwarf
. unit
. add ( self . entry_id , gimli ::DW_TAG_variable ) ;
let var_entry = self . debug_context . dwarf . unit . get_mut ( var_id ) ;
var_entry . set (
gimli ::DW_AT_name ,
AttributeValue ::String ( name . into_bytes ( ) ) ,
) ;
var_entry . set (
gimli ::DW_AT_type ,
AttributeValue ::ThisUnitEntryRef ( dw_ty ) ,
) ;
var_id
}
2019-01-17 18:07:27 +01:00
pub fn define (
& mut self ,
context : & Context ,
2019-05-31 10:56:55 +02:00
isa : & dyn cranelift ::codegen ::isa ::TargetIsa ,
2019-10-25 21:24:50 +02:00
source_info_set : & indexmap ::IndexSet < ( Span , mir ::SourceScope ) > ,
2019-01-17 18:07:27 +01:00
) {
2019-11-12 21:10:51 +01:00
let end = self . create_debug_lines ( context , isa , source_info_set ) ;
self . debug_context
. unit_range_list
. 0
. push ( Range ::StartLength {
begin : Address ::Symbol {
symbol : self . symbol ,
addend : 0 ,
} ,
length : end as u64 ,
} ) ;
2019-01-19 16:16:30 +01:00
2019-11-09 16:42:21 +01:00
{
let value_labels_ranges = context . build_value_labels_ranges ( isa ) . unwrap ( ) ;
for ( value_label , value_loc_ranges ) in value_labels_ranges . iter ( ) {
2019-11-12 20:43:34 +01:00
let var_id = self . define_local ( mir ::Local ::from_u32 ( value_label . as_u32 ( ) ) ) ;
2019-11-11 21:43:57 +01:00
let loc_list = LocationList (
2019-11-12 20:31:53 +01:00
value_loc_ranges
. iter ( )
. map ( | value_loc_range | {
Location ::StartEnd {
begin : Address ::Symbol {
symbol : self . symbol ,
addend : i64 ::from ( value_loc_range . start ) ,
} ,
end : Address ::Symbol {
symbol : self . symbol ,
addend : i64 ::from ( value_loc_range . end ) ,
} ,
2019-11-11 21:43:57 +01:00
data : Expression ( translate_loc ( value_loc_range . loc , & context . func . stack_slots ) . unwrap ( ) ) ,
2019-11-12 20:31:53 +01:00
}
} )
. collect ( ) ,
2019-11-11 21:43:57 +01:00
) ;
let loc_list_id = self . debug_context . dwarf . unit . locations . add ( loc_list ) ;
let var_entry = self . debug_context . dwarf . unit . get_mut ( var_id ) ;
var_entry . set (
gimli ::DW_AT_location ,
AttributeValue ::LocationListRef ( loc_list_id ) ,
) ;
2019-11-09 16:42:21 +01:00
}
}
2019-01-17 18:07:27 +01:00
}
}
2019-11-11 21:43:57 +01:00
// Adapted from https://github.com/CraneStation/wasmtime/blob/5a1845b4caf7a5dba8eda1fef05213a532ed4259/crates/debug/src/transform/expression.rs#L59-L137
fn map_reg ( reg : RegUnit ) -> Register {
static mut REG_X86_MAP : Option < HashMap < RegUnit , Register > > = None ;
// FIXME lazy initialization?
unsafe {
if REG_X86_MAP . is_none ( ) {
REG_X86_MAP = Some ( HashMap ::new ( ) ) ;
}
if let Some ( val ) = REG_X86_MAP . as_mut ( ) . unwrap ( ) . get ( & reg ) {
return * val ;
}
let result = match reg {
0 = > X86_64 ::RAX ,
1 = > X86_64 ::RCX ,
2 = > X86_64 ::RDX ,
3 = > X86_64 ::RBX ,
4 = > X86_64 ::RSP ,
5 = > X86_64 ::RBP ,
6 = > X86_64 ::RSI ,
7 = > X86_64 ::RDI ,
8 = > X86_64 ::R8 ,
9 = > X86_64 ::R9 ,
10 = > X86_64 ::R10 ,
11 = > X86_64 ::R11 ,
12 = > X86_64 ::R12 ,
13 = > X86_64 ::R13 ,
14 = > X86_64 ::R14 ,
15 = > X86_64 ::R15 ,
16 = > X86_64 ::XMM0 ,
17 = > X86_64 ::XMM1 ,
18 = > X86_64 ::XMM2 ,
19 = > X86_64 ::XMM3 ,
20 = > X86_64 ::XMM4 ,
21 = > X86_64 ::XMM5 ,
22 = > X86_64 ::XMM6 ,
23 = > X86_64 ::XMM7 ,
24 = > X86_64 ::XMM8 ,
25 = > X86_64 ::XMM9 ,
26 = > X86_64 ::XMM10 ,
27 = > X86_64 ::XMM11 ,
28 = > X86_64 ::XMM12 ,
29 = > X86_64 ::XMM13 ,
30 = > X86_64 ::XMM14 ,
31 = > X86_64 ::XMM15 ,
_ = > panic! ( " unknown x86_64 register {} " , reg ) ,
} ;
REG_X86_MAP . as_mut ( ) . unwrap ( ) . insert ( reg , result ) ;
result
}
}
fn translate_loc ( loc : ValueLoc , stack_slots : & StackSlots ) -> Option < Vec < u8 > > {
match loc {
ValueLoc ::Reg ( reg ) = > {
let machine_reg = map_reg ( reg ) . 0 as u8 ;
assert! ( machine_reg < = 32 ) ; // FIXME
Some ( vec! [ gimli ::constants ::DW_OP_reg0 . 0 + machine_reg ] )
}
ValueLoc ::Stack ( ss ) = > {
if let Some ( ss_offset ) = stack_slots [ ss ] . offset {
let endian = gimli ::RunTimeEndian ::Little ;
let mut writer = write ::EndianVec ::new ( endian ) ;
writer
. write_u8 ( gimli ::constants ::DW_OP_breg0 . 0 + X86_64 ::RBP . 0 as u8 )
. expect ( " bp wr " ) ;
writer . write_sleb128 ( ss_offset as i64 + 16 ) . expect ( " ss wr " ) ;
writer
. write_u8 ( gimli ::constants ::DW_OP_deref . 0 as u8 )
. expect ( " bp wr " ) ;
let buf = writer . into_vec ( ) ;
return Some ( buf ) ;
}
None
}
_ = > None ,
}
}