2020-09-23 15:13:49 +02:00
|
|
|
//! Line info generation (`.debug_line`)
|
|
|
|
|
2019-12-16 13:23:41 +01:00
|
|
|
use std::ffi::OsStr;
|
|
|
|
use std::path::{Component, Path};
|
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
use crate::debuginfo::FunctionDebugContext;
|
2019-11-12 21:08:08 +01:00
|
|
|
use crate::prelude::*;
|
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
use rustc_data_structures::sync::Lrc;
|
2020-08-28 12:10:48 +02:00
|
|
|
use rustc_span::{
|
|
|
|
FileName, Pos, SourceFile, SourceFileAndLine, SourceFileHash, SourceFileHashAlgorithm,
|
|
|
|
};
|
2019-11-12 21:08:08 +01:00
|
|
|
|
2019-12-24 12:40:18 +01:00
|
|
|
use cranelift_codegen::binemit::CodeOffset;
|
2021-07-07 11:14:20 +02:00
|
|
|
use cranelift_codegen::MachSrcLoc;
|
2019-11-12 21:10:51 +01:00
|
|
|
|
2019-11-12 21:08:08 +01:00
|
|
|
use gimli::write::{
|
2020-08-28 12:10:48 +02:00
|
|
|
Address, AttributeValue, FileId, FileInfo, LineProgram, LineString, LineStringTable,
|
2019-11-12 21:08:08 +01:00
|
|
|
};
|
|
|
|
|
2019-12-16 13:23:41 +01:00
|
|
|
// OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
|
|
|
|
fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
|
|
|
|
let mut iter = path.components();
|
|
|
|
let file_name = match iter.next_back() {
|
|
|
|
Some(Component::Normal(p)) => p,
|
|
|
|
component => {
|
2020-08-28 12:10:48 +02:00
|
|
|
panic!(
|
|
|
|
"Path component {:?} of path {} is an invalid filename",
|
|
|
|
component,
|
|
|
|
path.display()
|
|
|
|
);
|
2019-12-16 13:23:41 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let parent = iter.as_path();
|
|
|
|
(parent, file_name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// OPTIMIZATION: Avoid UTF-8 validation on UNIX.
|
|
|
|
fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
|
2020-08-28 12:10:48 +02:00
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
2019-12-16 13:23:41 +01:00
|
|
|
use std::os::unix::ffi::OsStrExt;
|
2021-03-29 10:45:09 +02:00
|
|
|
path.as_bytes()
|
2019-12-16 13:23:41 +01:00
|
|
|
}
|
2020-08-28 12:10:48 +02:00
|
|
|
#[cfg(not(unix))]
|
|
|
|
{
|
2021-03-29 10:45:09 +02:00
|
|
|
path.to_str().unwrap().as_bytes()
|
2019-12-16 13:23:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
const MD5_LEN: usize = 16;
|
2020-04-18 16:16:17 +03:00
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
fn make_file_info(hash: SourceFileHash) -> Option<FileInfo> {
|
2020-04-18 17:43:00 +03:00
|
|
|
if hash.kind == SourceFileHashAlgorithm::Md5 {
|
|
|
|
let mut buf = [0u8; MD5_LEN];
|
|
|
|
buf.copy_from_slice(hash.hash_bytes());
|
2021-03-05 19:12:59 +01:00
|
|
|
Some(FileInfo { timestamp: 0, size: 0, md5: buf })
|
2020-04-18 17:43:00 +03:00
|
|
|
} else {
|
|
|
|
None
|
2020-04-18 16:33:01 +03:00
|
|
|
}
|
2020-04-18 16:16:17 +03:00
|
|
|
}
|
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
impl DebugContext {
|
|
|
|
pub(crate) fn get_span_loc(
|
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
function_span: Span,
|
|
|
|
span: Span,
|
|
|
|
) -> (Lrc<SourceFile>, u64, u64) {
|
|
|
|
// Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
|
|
|
|
// In order to have a good line stepping behavior in debugger, we overwrite debug
|
2022-07-21 16:19:22 +01:00
|
|
|
// locations of macro expansions with that of the outermost expansion site (when the macro is
|
|
|
|
// annotated with `#[collapse_debuginfo]` or when `-Zdebug-macros` is provided).
|
|
|
|
let span = if tcx.should_collapse_debuginfo(span) {
|
2022-08-24 18:40:58 +02:00
|
|
|
span
|
|
|
|
} else {
|
|
|
|
// Walk up the macro expansion chain until we reach a non-expanded span.
|
|
|
|
// We also stop at the function body level because no line stepping can occur
|
|
|
|
// at the level above that.
|
|
|
|
rustc_span::hygiene::walk_chain(span, function_span.ctxt())
|
|
|
|
};
|
2020-04-18 14:56:04 +03:00
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
match tcx.sess.source_map().lookup_line(span.lo()) {
|
|
|
|
Ok(SourceFileAndLine { sf: file, line }) => {
|
2023-08-31 22:12:47 +02:00
|
|
|
let line_pos = file.lines()[line];
|
2023-09-03 10:15:35 +00:00
|
|
|
let col = file.relative_position(span.lo()) - line_pos;
|
2020-04-18 14:56:04 +03:00
|
|
|
|
2023-09-03 10:15:35 +00:00
|
|
|
(file, u64::try_from(line).unwrap() + 1, u64::from(col.to_u32()) + 1)
|
2022-08-24 18:40:58 +02:00
|
|
|
}
|
|
|
|
Err(file) => (file, 0, 0),
|
2019-11-12 21:08:08 +01:00
|
|
|
}
|
2022-08-24 18:40:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn add_source_file(&mut self, source_file: &SourceFile) -> FileId {
|
|
|
|
let line_program: &mut LineProgram = &mut self.dwarf.unit.line_program;
|
|
|
|
let line_strings: &mut LineStringTable = &mut self.dwarf.line_strings;
|
|
|
|
|
|
|
|
match &source_file.name {
|
|
|
|
FileName::Real(path) => {
|
|
|
|
let (dir_path, file_name) =
|
|
|
|
split_path_dir_and_file(path.remapped_path_if_available());
|
|
|
|
let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
|
|
|
|
let file_name = osstr_as_utf8_bytes(file_name);
|
|
|
|
|
|
|
|
let dir_id = if !dir_name.is_empty() {
|
|
|
|
let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
|
|
|
|
line_program.add_directory(dir_name)
|
|
|
|
} else {
|
|
|
|
line_program.default_directory()
|
|
|
|
};
|
|
|
|
let file_name = LineString::new(file_name, line_program.encoding(), line_strings);
|
|
|
|
|
|
|
|
let info = make_file_info(source_file.src_hash);
|
|
|
|
|
|
|
|
line_program.file_has_md5 &= info.is_some();
|
|
|
|
line_program.add_file(file_name, dir_id, info)
|
|
|
|
}
|
|
|
|
// FIXME give more appropriate file names
|
|
|
|
filename => {
|
|
|
|
let dir_id = line_program.default_directory();
|
|
|
|
let dummy_file_name = LineString::new(
|
|
|
|
filename.prefer_remapped().to_string().into_bytes(),
|
|
|
|
line_program.encoding(),
|
|
|
|
line_strings,
|
|
|
|
);
|
|
|
|
line_program.add_file(dummy_file_name, dir_id, None)
|
|
|
|
}
|
2019-11-12 21:08:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
impl FunctionDebugContext {
|
|
|
|
pub(crate) fn add_dbg_loc(&mut self, file_id: FileId, line: u64, column: u64) -> SourceLoc {
|
|
|
|
let (index, _) = self.source_loc_set.insert_full((file_id, line, column));
|
|
|
|
SourceLoc::new(u32::try_from(index).unwrap())
|
2019-11-12 21:08:08 +01:00
|
|
|
}
|
|
|
|
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) fn create_debug_lines(
|
2019-11-12 21:08:08 +01:00
|
|
|
&mut self,
|
2022-08-24 18:40:58 +02:00
|
|
|
debug_context: &mut DebugContext,
|
2020-06-13 17:03:34 +02:00
|
|
|
symbol: usize,
|
|
|
|
context: &Context,
|
2019-11-12 21:10:51 +01:00
|
|
|
) -> CodeOffset {
|
2022-08-24 18:40:58 +02:00
|
|
|
let create_row_for_span =
|
|
|
|
|debug_context: &mut DebugContext, source_loc: (FileId, u64, u64)| {
|
|
|
|
let (file_id, line, col) = source_loc;
|
|
|
|
|
|
|
|
debug_context.dwarf.unit.line_program.row().file = file_id;
|
|
|
|
debug_context.dwarf.unit.line_program.row().line = line;
|
|
|
|
debug_context.dwarf.unit.line_program.row().column = col;
|
|
|
|
debug_context.dwarf.unit.line_program.generate_row();
|
2020-03-14 14:48:04 +01:00
|
|
|
};
|
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
debug_context
|
|
|
|
.dwarf
|
|
|
|
.unit
|
|
|
|
.line_program
|
|
|
|
.begin_sequence(Some(Address::Symbol { symbol, addend: 0 }));
|
2020-04-25 14:17:09 +02:00
|
|
|
|
|
|
|
let mut func_end = 0;
|
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
let mcr = context.compiled_code().unwrap();
|
2021-03-05 19:12:59 +01:00
|
|
|
for &MachSrcLoc { start, end, loc } in mcr.buffer.get_srclocs_sorted() {
|
2022-08-24 18:40:58 +02:00
|
|
|
debug_context.dwarf.unit.line_program.row().address_offset = u64::from(start);
|
2021-03-05 19:12:59 +01:00
|
|
|
if !loc.is_default() {
|
2023-07-22 13:32:34 +00:00
|
|
|
let source_loc = self.source_loc_set[loc.bits() as usize];
|
2022-08-24 18:40:58 +02:00
|
|
|
create_row_for_span(debug_context, source_loc);
|
2021-03-05 19:12:59 +01:00
|
|
|
} else {
|
2022-08-24 18:40:58 +02:00
|
|
|
create_row_for_span(debug_context, self.function_source_loc);
|
2019-11-12 21:08:08 +01:00
|
|
|
}
|
2021-03-05 19:12:59 +01:00
|
|
|
func_end = end;
|
2019-11-12 21:08:08 +01:00
|
|
|
}
|
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
debug_context.dwarf.unit.line_program.end_sequence(u64::from(func_end));
|
2021-03-05 19:12:59 +01:00
|
|
|
|
|
|
|
let func_end = mcr.buffer.total_size();
|
|
|
|
|
2020-04-25 14:17:09 +02:00
|
|
|
assert_ne!(func_end, 0);
|
|
|
|
|
2022-08-24 18:40:58 +02:00
|
|
|
let entry = debug_context.dwarf.unit.get_mut(self.entry_id);
|
2019-11-12 21:08:08 +01:00
|
|
|
entry.set(
|
|
|
|
gimli::DW_AT_low_pc,
|
2020-08-28 12:10:48 +02:00
|
|
|
AttributeValue::Address(Address::Symbol { symbol, addend: 0 }),
|
|
|
|
);
|
2021-03-05 19:12:59 +01:00
|
|
|
entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(u64::from(func_end)));
|
2019-11-12 21:08:08 +01:00
|
|
|
|
2020-04-25 14:17:09 +02:00
|
|
|
func_end
|
2019-11-12 21:08:08 +01:00
|
|
|
}
|
|
|
|
}
|