]> git.lizzy.rs Git - rust.git/blob - src/debuginfo/line_info.rs
Rustup to rustc 1.45.0-nightly (56daaf669 2020-06-03)
[rust.git] / src / debuginfo / line_info.rs
1 use std::ffi::OsStr;
2 use std::path::{Component, Path};
3
4 use crate::prelude::*;
5
6 use rustc_span::{FileName, SourceFile, SourceFileAndLine, Pos, SourceFileHash, SourceFileHashAlgorithm};
7
8 use cranelift_codegen::binemit::CodeOffset;
9 use cranelift_codegen::machinst::MachSrcLoc;
10
11 use gimli::write::{
12     Address, AttributeValue, FileId, LineProgram, LineString, FileInfo, LineStringTable, UnitEntryId,
13 };
14
15 // OPTIMIZATION: It is cheaper to do this in one pass than using `.parent()` and `.file_name()`.
16 fn split_path_dir_and_file(path: &Path) -> (&Path, &OsStr) {
17     let mut iter = path.components();
18     let file_name = match iter.next_back() {
19         Some(Component::Normal(p)) => p,
20         component => {
21             panic!("Path component {:?} of path {} is an invalid filename", component, path.display());
22         }
23     };
24     let parent = iter.as_path();
25     (parent, file_name)
26 }
27
28 // OPTIMIZATION: Avoid UTF-8 validation on UNIX.
29 fn osstr_as_utf8_bytes(path: &OsStr) -> &[u8] {
30     #[cfg(unix)] {
31         use std::os::unix::ffi::OsStrExt;
32         return path.as_bytes();
33     }
34     #[cfg(not(unix))] {
35         return path.to_str().unwrap().as_bytes();
36     }
37 }
38
39 pub(crate) const MD5_LEN: usize = 16;
40
41 pub fn make_file_info(hash: SourceFileHash) -> Option<FileInfo> {
42     if hash.kind == SourceFileHashAlgorithm::Md5 {
43         let mut buf = [0u8; MD5_LEN];
44         buf.copy_from_slice(hash.hash_bytes());
45         Some(FileInfo {
46             timestamp: 0,
47             size: 0,
48             md5: buf,
49         })
50     } else {
51         None
52     }
53 }
54
55 fn line_program_add_file(
56     line_program: &mut LineProgram,
57     line_strings: &mut LineStringTable,
58     file: &SourceFile,
59 ) -> FileId {
60     match &file.name {
61         FileName::Real(path) => {
62             let (dir_path, file_name) = split_path_dir_and_file(path.stable_name());
63             let dir_name = osstr_as_utf8_bytes(dir_path.as_os_str());
64             let file_name = osstr_as_utf8_bytes(file_name);
65
66             let dir_id = if !dir_name.is_empty() {
67                 let dir_name = LineString::new(dir_name, line_program.encoding(), line_strings);
68                 line_program.add_directory(dir_name)
69             } else {
70                 line_program.default_directory()
71             };
72             let file_name = LineString::new(
73                 file_name,
74                 line_program.encoding(),
75                 line_strings,
76             );
77
78             let info = make_file_info(file.src_hash);
79
80             line_program.file_has_md5 &= info.is_some();
81             line_program.add_file(file_name, dir_id, info)
82         }
83         // FIXME give more appropriate file names
84         filename => {
85             let dir_id = line_program.default_directory();
86             let dummy_file_name = LineString::new(
87                 filename.to_string().into_bytes(),
88                 line_program.encoding(),
89                 line_strings,
90             );
91             line_program.add_file(dummy_file_name, dir_id, None)
92         }
93     }
94 }
95
96 impl<'tcx> DebugContext<'tcx> {
97     pub(super) fn emit_location(&mut self, entry_id: UnitEntryId, span: Span) {
98         let loc = self.tcx.sess.source_map().lookup_char_pos(span.lo());
99
100         let file_id = line_program_add_file(
101             &mut self.dwarf.unit.line_program,
102             &mut self.dwarf.line_strings,
103             &loc.file,
104         );
105
106         let entry = self.dwarf.unit.get_mut(entry_id);
107
108         entry.set(
109             gimli::DW_AT_decl_file,
110             AttributeValue::FileIndex(Some(file_id)),
111         );
112         entry.set(
113             gimli::DW_AT_decl_line,
114             AttributeValue::Udata(loc.line as u64),
115         );
116         // FIXME: probably omit this
117         entry.set(
118             gimli::DW_AT_decl_column,
119             AttributeValue::Udata(loc.col.to_usize() as u64),
120         );
121     }
122 }
123
124 impl<'a, 'tcx> FunctionDebugContext<'a, 'tcx> {
125     pub(super) fn create_debug_lines(
126         &mut self,
127         context: &Context,
128         isa: &dyn cranelift_codegen::isa::TargetIsa,
129         source_info_set: &indexmap::IndexSet<SourceInfo>,
130     ) -> CodeOffset {
131         let tcx = self.debug_context.tcx;
132         let line_program = &mut self.debug_context.dwarf.unit.line_program;
133         let func = &context.func;
134
135         let line_strings = &mut self.debug_context.dwarf.line_strings;
136         let function_span = self.mir.span;
137         let mut last_span = None;
138         let mut last_file = None;
139         let mut create_row_for_span = |line_program: &mut LineProgram, span: Span| {
140             if let Some(last_span) = last_span {
141                 if span == last_span {
142                     line_program.generate_row();
143                     return;
144                 }
145             }
146             last_span = Some(span);
147
148             // Based on https://github.com/rust-lang/rust/blob/e369d87b015a84653343032833d65d0545fd3f26/src/librustc_codegen_ssa/mir/mod.rs#L116-L131
149             // In order to have a good line stepping behavior in debugger, we overwrite debug
150             // locations of macro expansions with that of the outermost expansion site
151             // (unless the crate is being compiled with `-Z debug-macros`).
152             let span = if !span.from_expansion() ||
153                 tcx.sess.opts.debugging_opts.debug_macros {
154                 span
155             } else {
156                 // Walk up the macro expansion chain until we reach a non-expanded span.
157                 // We also stop at the function body level because no line stepping can occur
158                 // at the level above that.
159                 rustc_span::hygiene::walk_chain(span, function_span.ctxt())
160             };
161
162             let (file, line, col) = match tcx.sess.source_map().lookup_line(span.lo()) {
163                 Ok(SourceFileAndLine { sf: file, line }) => {
164                     let line_pos = file.line_begin_pos(span.lo());
165
166                     (file, u64::try_from(line).unwrap() + 1, u64::from((span.lo() - line_pos).to_u32()) + 1)
167                 }
168                 Err(file) => (file, 0, 0)
169             };
170
171             // line_program_add_file is very slow.
172             // Optimize for the common case of the current file not being changed.
173             let current_file_changed = if let Some(last_file) = &last_file {
174                 // If the allocations are not equal, then the files may still be equal, but that
175                 // is not a problem, as this is just an optimization.
176                 !rustc_data_structures::sync::Lrc::ptr_eq(last_file, &file)
177             } else {
178                 true
179             };
180             if current_file_changed {
181                 let file_id = line_program_add_file(line_program, line_strings, &file);
182                 line_program.row().file = file_id;
183                 last_file = Some(file.clone());
184             }
185
186             line_program.row().line = line;
187             line_program.row().column = col;
188             line_program.generate_row();
189         };
190
191         line_program.begin_sequence(Some(Address::Symbol {
192             symbol: self.symbol,
193             addend: 0,
194         }));
195
196         let mut func_end = 0;
197
198         if let Some(ref mcr) = &context.mach_compile_result {
199             for &MachSrcLoc { start, end, loc } in mcr.buffer.get_srclocs_sorted() {
200                 line_program.row().address_offset = start as u64;
201                 if !loc.is_default() {
202                     let source_info = *source_info_set.get_index(loc.bits() as usize).unwrap();
203                     create_row_for_span(line_program, source_info.span);
204                 } else {
205                     create_row_for_span(line_program, self.mir.span);
206                 }
207                 func_end = end;
208             }
209
210             line_program.end_sequence(func_end as u64);
211
212             func_end = mcr.buffer.total_size();
213         } else {
214             let encinfo = isa.encoding_info();
215             let mut blocks = func.layout.blocks().collect::<Vec<_>>();
216             blocks.sort_by_key(|block| func.offsets[*block]); // Ensure inst offsets always increase
217
218             for block in blocks {
219                 for (offset, inst, size) in func.inst_offsets(block, &encinfo) {
220                     let srcloc = func.srclocs[inst];
221                     line_program.row().address_offset = offset as u64;
222                     if !srcloc.is_default() {
223                         let source_info = *source_info_set.get_index(srcloc.bits() as usize).unwrap();
224                         create_row_for_span(line_program, source_info.span);
225                     } else {
226                         create_row_for_span(line_program, self.mir.span);
227                     }
228                     func_end = offset + size;
229                 }
230             }
231             line_program.end_sequence(func_end as u64);
232         }
233
234         assert_ne!(func_end, 0);
235
236         let entry = self.debug_context.dwarf.unit.get_mut(self.entry_id);
237         entry.set(
238             gimli::DW_AT_low_pc,
239             AttributeValue::Address(Address::Symbol {
240                 symbol: self.symbol,
241                 addend: 0,
242             }),
243         );
244         entry.set(gimli::DW_AT_high_pc, AttributeValue::Udata(func_end as u64));
245
246         self.debug_context
247             .emit_location(self.entry_id, self.mir.span);
248
249         func_end
250     }
251 }