2020-09-23 15:13:49 +02:00
//! Handling of everything related to debuginfo.
2019-11-12 20:52:32 +01:00
mod emit ;
2019-11-12 21:08:08 +01:00
mod line_info ;
2021-09-19 13:56:58 +02:00
mod object ;
2024-03-28 11:43:35 +00:00
mod types ;
2020-04-25 18:23:31 +02:00
mod unwind ;
2019-01-17 18:07:27 +01:00
2022-08-24 18:40:58 +02:00
use cranelift_codegen ::ir ::Endianness ;
2020-04-01 14:12:46 +02:00
use cranelift_codegen ::isa ::TargetIsa ;
2024-03-28 11:43:35 +00:00
use cranelift_module ::DataId ;
2019-01-17 18:07:27 +01:00
use gimli ::write ::{
2024-03-28 11:43:35 +00:00
Address , AttributeValue , DwarfUnit , Expression , FileId , LineProgram , LineString , Range ,
RangeList , UnitEntryId ,
2019-01-17 18:07:27 +01:00
} ;
2024-03-28 11:43:35 +00:00
use gimli ::{ AArch64 , Encoding , Format , LineEncoding , Register , RiscV , RunTimeEndian , X86_64 } ;
2022-08-24 18:40:58 +02:00
use indexmap ::IndexSet ;
2024-03-28 11:43:35 +00:00
use rustc_codegen_ssa ::debuginfo ::type_names ;
use rustc_hir ::def ::DefKind ;
use rustc_hir ::def_id ::DefIdMap ;
2024-01-26 18:33:45 +00:00
use rustc_session ::Session ;
2024-04-23 09:37:28 +00:00
use rustc_span ::{ FileNameDisplayPreference , SourceFileHash , StableSourceFileId } ;
2024-11-09 13:48:06 +00:00
use rustc_target ::callconv ::FnAbi ;
2019-11-12 20:52:32 +01:00
2023-10-09 08:52:46 +00:00
pub ( crate ) use self ::emit ::{ DebugReloc , DebugRelocName } ;
2024-03-28 11:43:35 +00:00
pub ( crate ) use self ::types ::TypeDebugContext ;
2023-10-09 08:52:46 +00:00
pub ( crate ) use self ::unwind ::UnwindContext ;
2024-03-28 11:43:35 +00:00
use crate ::debuginfo ::emit ::{ address_for_data , address_for_func } ;
2023-10-09 08:52:46 +00:00
use crate ::prelude ::* ;
2019-01-17 18:07:27 +01:00
2024-01-26 18:33:45 +00:00
pub ( crate ) fn producer ( sess : & Session ) -> String {
format! ( " rustc version {} with cranelift {} " , sess . cfg_version , cranelift_codegen ::VERSION )
2023-01-24 18:56:42 +01:00
}
2022-08-24 18:40:58 +02:00
pub ( crate ) struct DebugContext {
2019-01-17 18:07:27 +01:00
endian : RunTimeEndian ,
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 ,
2024-03-28 11:43:35 +00:00
created_files : FxHashMap < ( StableSourceFileId , SourceFileHash ) , FileId > ,
stack_pointer_register : Register ,
namespace_map : DefIdMap < UnitEntryId > ,
array_size_type : UnitEntryId ,
2023-08-23 15:46:58 +02:00
2024-03-22 15:27:17 +01:00
filename_display_preference : FileNameDisplayPreference ,
2022-08-24 18:40:58 +02:00
}
2019-01-17 18:07:27 +01:00
2022-08-24 18:40:58 +02:00
pub ( crate ) struct FunctionDebugContext {
entry_id : UnitEntryId ,
function_source_loc : ( FileId , u64 , u64 ) ,
2023-07-22 13:32:34 +00:00
source_loc_set : IndexSet < ( FileId , u64 , u64 ) > ,
2019-01-17 18:07:27 +01:00
}
2022-08-24 18:40:58 +02:00
impl DebugContext {
2024-03-28 11:43:35 +00:00
pub ( crate ) fn new ( tcx : TyCtxt < '_ > , isa : & dyn TargetIsa , cgu_name : & str ) -> Self {
2019-01-26 12:37:49 +01:00
let encoding = Encoding {
format : Format ::Dwarf32 ,
2021-08-06 16:26:56 +02:00
// FIXME this should be configurable
2019-01-26 12:37:49 +01:00
// macOS doesn't seem to support DWARF > 3
2020-04-18 14:56:04 +03:00
// 5 version is required for md5 file hash
2024-08-19 15:20:02 +02:00
version : if tcx . sess . target . is_like_darwin {
2020-04-18 16:05:20 +03:00
3
} else {
2020-04-21 12:13:50 +02:00
// FIXME change to version 5 once the gdb and lldb shipping with the latest debian
// support it.
4
2020-04-18 16:05:20 +03:00
} ,
2020-04-25 18:23:31 +02:00
address_size : isa . frontend_config ( ) . pointer_bytes ( ) ,
2019-01-26 12:37:49 +01:00
} ;
2019-01-17 18:07:27 +01:00
2021-12-30 14:53:41 +01:00
let endian = match isa . endianness ( ) {
Endianness ::Little = > RunTimeEndian ::Little ,
Endianness ::Big = > RunTimeEndian ::Big ,
} ;
2024-03-28 11:43:35 +00:00
let stack_pointer_register = match isa . triple ( ) . architecture {
target_lexicon ::Architecture ::Aarch64 ( _ ) = > AArch64 ::SP ,
target_lexicon ::Architecture ::Riscv64 ( _ ) = > RiscV ::SP ,
target_lexicon ::Architecture ::X86_64 | target_lexicon ::Architecture ::X86_64h = > {
X86_64 ::RSP
}
_ = > Register ( u16 ::MAX ) ,
} ;
2019-02-09 17:15:15 +10:00
let mut dwarf = DwarfUnit ::new ( encoding ) ;
2024-03-19 13:51:22 +01:00
use rustc_session ::config ::RemapPathScopeComponents ;
2024-03-21 21:13:06 +01:00
2024-03-22 15:27:17 +01:00
let filename_display_preference =
tcx . sess . filename_display_preference ( RemapPathScopeComponents ::DEBUGINFO ) ;
2023-08-23 15:46:58 +02:00
2024-01-26 18:33:45 +00:00
let producer = producer ( tcx . sess ) ;
2024-03-22 15:27:17 +01:00
let comp_dir =
tcx . sess . opts . working_dir . to_string_lossy ( filename_display_preference ) . to_string ( ) ;
2024-03-19 13:51:22 +01:00
2022-12-07 09:24:00 +00:00
let ( name , file_info ) = match tcx . sess . local_crate_source_file ( ) {
2020-04-18 14:56:04 +03:00
Some ( path ) = > {
2024-03-22 15:27:17 +01:00
let name = path . to_string_lossy ( filename_display_preference ) . to_string ( ) ;
2020-06-04 19:57:12 +02:00
( name , None )
2020-08-28 12:10:48 +02:00
}
2020-04-18 14:56:04 +03:00
None = > ( tcx . crate_name ( LOCAL_CRATE ) . to_string ( ) , None ) ,
2019-01-17 18:07:27 +01:00
} ;
2024-11-02 14:53:30 +00:00
let file_has_md5 = file_info . is_some ( ) ;
2020-04-18 14:56:04 +03:00
let mut 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 ) ,
2020-04-18 17:43:00 +03:00
file_info ,
2019-02-09 17:15:15 +10:00
) ;
2024-11-02 14:53:30 +00:00
line_program . file_has_md5 = file_has_md5 ;
2020-04-18 14:56:04 +03:00
2019-02-09 17:15:15 +10:00
dwarf . unit . line_program = line_program ;
2019-01-17 18:07:27 +01:00
{
2024-03-28 11:43:35 +00:00
let name = dwarf . strings . add ( format! ( " {name} /@/ {cgu_name} " ) ) ;
2020-03-07 11:27:49 +01:00
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 ) ;
2021-03-05 19:12:59 +01:00
root . set ( gimli ::DW_AT_producer , AttributeValue ::StringRef ( dwarf . strings . add ( producer ) ) ) ;
root . set ( gimli ::DW_AT_language , AttributeValue ::Language ( gimli ::DW_LANG_Rust ) ) ;
2019-01-17 18:07:27 +01:00
root . set ( gimli ::DW_AT_name , AttributeValue ::StringRef ( name ) ) ;
2024-03-28 11:43:35 +00:00
// This will be replaced when emitting the debuginfo. It is only
// defined here to ensure that the order of the attributes matches
// rustc.
root . set ( gimli ::DW_AT_stmt_list , AttributeValue ::Udata ( 0 ) ) ;
2019-01-17 18:07:27 +01:00
root . set ( gimli ::DW_AT_comp_dir , AttributeValue ::StringRef ( comp_dir ) ) ;
2021-03-05 19:12:59 +01:00
root . set ( gimli ::DW_AT_low_pc , AttributeValue ::Address ( Address ::Constant ( 0 ) ) ) ;
2019-01-17 18:07:27 +01:00
}
2024-03-28 11:43:35 +00:00
let array_size_type = dwarf . unit . add ( dwarf . unit . root ( ) , gimli ::DW_TAG_base_type ) ;
let array_size_type_entry = dwarf . unit . get_mut ( array_size_type ) ;
array_size_type_entry . set (
gimli ::DW_AT_name ,
AttributeValue ::StringRef ( dwarf . strings . add ( " __ARRAY_SIZE_TYPE__ " ) ) ,
) ;
array_size_type_entry
. set ( gimli ::DW_AT_encoding , AttributeValue ::Encoding ( gimli ::DW_ATE_unsigned ) ) ;
array_size_type_entry . set (
gimli ::DW_AT_byte_size ,
AttributeValue ::Udata ( isa . frontend_config ( ) . pointer_bytes ( ) . into ( ) ) ,
) ;
2023-08-23 15:46:58 +02:00
DebugContext {
endian ,
dwarf ,
unit_range_list : RangeList ( Vec ::new ( ) ) ,
2024-03-28 11:43:35 +00:00
created_files : FxHashMap ::default ( ) ,
stack_pointer_register ,
namespace_map : DefIdMap ::default ( ) ,
array_size_type ,
2024-03-22 15:27:17 +01:00
filename_display_preference ,
2023-08-23 15:46:58 +02:00
}
2020-06-13 17:03:34 +02:00
}
2024-03-28 11:43:35 +00:00
fn item_namespace ( & mut self , tcx : TyCtxt < '_ > , def_id : DefId ) -> UnitEntryId {
if let Some ( & scope ) = self . namespace_map . get ( & def_id ) {
return scope ;
}
let def_key = tcx . def_key ( def_id ) ;
let parent_scope = def_key
. parent
. map ( | parent | self . item_namespace ( tcx , DefId { krate : def_id . krate , index : parent } ) )
. unwrap_or ( self . dwarf . unit . root ( ) ) ;
let namespace_name = {
let mut output = String ::new ( ) ;
type_names ::push_item_name ( tcx , def_id , false , & mut output ) ;
output
} ;
let namespace_name_id = self . dwarf . strings . add ( namespace_name ) ;
let scope = self . dwarf . unit . add ( parent_scope , gimli ::DW_TAG_namespace ) ;
let scope_entry = self . dwarf . unit . get_mut ( scope ) ;
scope_entry . set ( gimli ::DW_AT_name , AttributeValue ::StringRef ( namespace_name_id ) ) ;
self . namespace_map . insert ( def_id , scope ) ;
scope
}
pub ( crate ) fn define_function < ' tcx > (
2020-06-13 17:03:34 +02:00
& mut self ,
2024-03-28 11:43:35 +00:00
tcx : TyCtxt < ' tcx > ,
type_dbg : & mut TypeDebugContext < ' tcx > ,
instance : Instance < ' tcx > ,
fn_abi : & ' tcx FnAbi < ' tcx , Ty < ' tcx > > ,
linkage_name : & str ,
2022-08-24 18:40:58 +02:00
function_span : Span ,
) -> FunctionDebugContext {
2024-03-28 11:43:35 +00:00
let ( file_id , line , column ) = self . get_span_loc ( tcx , function_span , function_span ) ;
let scope = self . item_namespace ( tcx , tcx . parent ( instance . def_id ( ) ) ) ;
let mut name = String ::new ( ) ;
type_names ::push_item_name ( tcx , instance . def_id ( ) , false , & mut name ) ;
2022-08-24 18:40:58 +02:00
2024-03-28 11:43:35 +00:00
// Find the enclosing function, in case this is a closure.
let enclosing_fn_def_id = tcx . typeck_root_def_id ( instance . def_id ( ) ) ;
2019-11-11 20:49:20 +01:00
2024-03-28 11:43:35 +00:00
// We look up the generics of the enclosing function and truncate the args
// to their length in order to cut off extra stuff that might be in there for
// closures or coroutines.
let generics = tcx . generics_of ( enclosing_fn_def_id ) ;
let args = instance . args . truncate_to ( tcx , generics ) ;
type_names ::push_generic_params (
tcx ,
2024-11-15 13:53:31 +01:00
tcx . normalize_erasing_regions ( ty ::TypingEnv ::fully_monomorphized ( ) , args ) ,
2024-03-28 11:43:35 +00:00
& mut name ,
) ;
2019-01-17 18:07:27 +01:00
2020-08-28 12:10:48 +02:00
let entry_id = self . dwarf . unit . add ( scope , gimli ::DW_TAG_subprogram ) ;
2020-06-13 17:03:34 +02:00
let entry = self . dwarf . unit . get_mut ( entry_id ) ;
2024-03-28 11:43:35 +00:00
let linkage_name_id =
if name ! = linkage_name { Some ( self . dwarf . strings . add ( linkage_name ) ) } else { None } ;
2020-06-13 17:03:34 +02:00
let name_id = self . dwarf . strings . add ( name ) ;
2024-03-28 11:43:35 +00:00
// These will be replaced in FunctionDebugContext::finalize. They are
// only defined here to ensure that the order of the attributes matches
// rustc.
entry . set ( gimli ::DW_AT_low_pc , AttributeValue ::Udata ( 0 ) ) ;
entry . set ( gimli ::DW_AT_high_pc , AttributeValue ::Udata ( 0 ) ) ;
let mut frame_base_expr = Expression ::new ( ) ;
frame_base_expr . op_reg ( self . stack_pointer_register ) ;
entry . set ( gimli ::DW_AT_frame_base , AttributeValue ::Exprloc ( frame_base_expr ) ) ;
if let Some ( linkage_name_id ) = linkage_name_id {
entry . set ( gimli ::DW_AT_linkage_name , AttributeValue ::StringRef ( linkage_name_id ) ) ;
}
2020-04-23 16:44:12 +02:00
// Gdb requires DW_AT_name. Otherwise the DW_TAG_subprogram is skipped.
2020-08-28 12:10:48 +02:00
entry . set ( gimli ::DW_AT_name , AttributeValue ::StringRef ( name_id ) ) ;
2019-01-17 18:07:27 +01:00
2022-08-24 18:40:58 +02:00
entry . set ( gimli ::DW_AT_decl_file , AttributeValue ::FileIndex ( Some ( file_id ) ) ) ;
entry . set ( gimli ::DW_AT_decl_line , AttributeValue ::Udata ( line ) ) ;
2024-03-28 11:43:35 +00:00
if ! fn_abi . ret . is_ignore ( ) {
let return_dw_ty = self . debug_type ( tcx , type_dbg , fn_abi . ret . layout . ty ) ;
let entry = self . dwarf . unit . get_mut ( entry_id ) ;
entry . set ( gimli ::DW_AT_type , AttributeValue ::UnitRef ( return_dw_ty ) ) ;
}
if tcx . is_reachable_non_generic ( instance . def_id ( ) ) {
let entry = self . dwarf . unit . get_mut ( entry_id ) ;
entry . set ( gimli ::DW_AT_external , AttributeValue ::FlagPresent ) ;
}
2019-11-12 21:10:51 +01:00
2022-08-24 18:40:58 +02:00
FunctionDebugContext {
entry_id ,
function_source_loc : ( file_id , line , column ) ,
source_loc_set : IndexSet ::new ( ) ,
}
}
2024-03-28 11:43:35 +00:00
// Adapted from https://github.com/rust-lang/rust/blob/10a7aa14fed9b528b74b0f098c4899c37c09a9c7/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs#L1288-L1346
pub ( crate ) fn define_static < ' tcx > (
& mut self ,
tcx : TyCtxt < ' tcx > ,
type_dbg : & mut TypeDebugContext < ' tcx > ,
def_id : DefId ,
data_id : DataId ,
) {
let DefKind ::Static { nested , .. } = tcx . def_kind ( def_id ) else { bug! ( ) } ;
if nested {
return ;
}
let scope = self . item_namespace ( tcx , tcx . parent ( def_id ) ) ;
let span = tcx . def_span ( def_id ) ;
let ( file_id , line , _column ) = self . get_span_loc ( tcx , span , span ) ;
2024-11-15 13:53:31 +01:00
let static_type = Instance ::mono ( tcx , def_id ) . ty ( tcx , ty ::TypingEnv ::fully_monomorphized ( ) ) ;
let static_layout = tcx
. layout_of ( ty ::TypingEnv ::fully_monomorphized ( ) . as_query_input ( static_type ) )
. unwrap ( ) ;
2024-03-28 11:43:35 +00:00
// FIXME use the actual type layout
let type_id = self . debug_type ( tcx , type_dbg , static_type ) ;
let name = tcx . item_name ( def_id ) ;
let linkage_name = tcx . symbol_name ( Instance ::mono ( tcx , def_id ) ) . name ;
let entry_id = self . dwarf . unit . add ( scope , gimli ::DW_TAG_variable ) ;
let entry = self . dwarf . unit . get_mut ( entry_id ) ;
let linkage_name_id = if name . as_str ( ) ! = linkage_name {
Some ( self . dwarf . strings . add ( linkage_name ) )
} else {
None
} ;
let name_id = self . dwarf . strings . add ( name . as_str ( ) ) ;
entry . set ( gimli ::DW_AT_name , AttributeValue ::StringRef ( name_id ) ) ;
entry . set ( gimli ::DW_AT_type , AttributeValue ::UnitRef ( type_id ) ) ;
if tcx . is_reachable_non_generic ( def_id ) {
entry . set ( gimli ::DW_AT_external , AttributeValue ::FlagPresent ) ;
}
entry . set ( gimli ::DW_AT_decl_file , AttributeValue ::FileIndex ( Some ( file_id ) ) ) ;
entry . set ( gimli ::DW_AT_decl_line , AttributeValue ::Udata ( line ) ) ;
2025-02-13 14:22:57 +00:00
entry . set ( gimli ::DW_AT_alignment , AttributeValue ::Udata ( static_layout . align . abi . bytes ( ) ) ) ;
2024-03-28 11:43:35 +00:00
let mut expr = Expression ::new ( ) ;
expr . op_addr ( address_for_data ( data_id ) ) ;
entry . set ( gimli ::DW_AT_location , AttributeValue ::Exprloc ( expr ) ) ;
if let Some ( linkage_name_id ) = linkage_name_id {
entry . set ( gimli ::DW_AT_linkage_name , AttributeValue ::StringRef ( linkage_name_id ) ) ;
}
}
2022-08-24 18:40:58 +02:00
}
impl FunctionDebugContext {
pub ( crate ) fn finalize (
mut self ,
debug_context : & mut DebugContext ,
func_id : FuncId ,
context : & Context ,
) {
2024-03-28 11:43:35 +00:00
let end = self . create_debug_lines ( debug_context , func_id , context ) ;
2022-08-24 18:40:58 +02:00
2024-03-28 11:43:35 +00:00
debug_context
. unit_range_list
. 0
. push ( Range ::StartLength { begin : address_for_func ( func_id ) , length : u64 ::from ( end ) } ) ;
2019-01-19 16:16:30 +01:00
2022-08-24 18:40:58 +02:00
let func_entry = debug_context . dwarf . unit . get_mut ( self . entry_id ) ;
2020-04-23 16:44:12 +02:00
// Gdb requires both DW_AT_low_pc and DW_AT_high_pc. Otherwise the DW_TAG_subprogram is skipped.
2024-03-28 11:43:35 +00:00
func_entry . set ( gimli ::DW_AT_low_pc , AttributeValue ::Address ( address_for_func ( func_id ) ) ) ;
2020-04-23 16:44:12 +02:00
// Using Udata for DW_AT_high_pc requires at least DWARF4
func_entry . set ( gimli ::DW_AT_high_pc , AttributeValue ::Udata ( u64 ::from ( end ) ) ) ;
2019-11-11 21:43:57 +01:00
}
}