-
Notifications
You must be signed in to change notification settings - Fork 243
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
analyze: emit inline annotations for debugging (#1071)
This branch adds a new `annotate` module that allows providing annotations to be attached to specific lines during rewriting, and uses it to show pointer permissions/flags inline in the rewritten code. For example: ```Rust #[no_mangle] pub unsafe extern "C" fn insertion_sort<'h0>(n: libc::c_int, p: &'h0 mut [(libc::c_int)]) { // 10: p: typeof(_2) = *mut {g0} i32 // 10: p: g0 = READ | WRITE | UNIQUE | OFFSET_ADD | OFFSET_SUB, (empty) let mut i: libc::c_int = 1 as libc::c_int; while i < n { let tmp: libc::c_int = *&(&(&*(p))[((i as isize) as usize) ..])[0]; // 15: p.offset(i as isize): typeof(_9) = *mut {l9} i32 // 15: p.offset(i as isize): l9 = READ | UNIQUE, (empty) // 15: p: typeof(_10) = *mut {l11} i32 // 15: p: l11 = READ | UNIQUE | OFFSET_ADD | OFFSET_SUB, (empty) let mut j: libc::c_int = i; while j > 0 as libc::c_int && *&(&(&*(p))[(((j - 1 as libc::c_int) as isize) as usize) ..])[0] > tmp { // 19: p.offset((j - 1 ... size): typeof(_21) = *mut {l23} i32 // 19: p.offset((j - 1 ... size): l23 = READ | UNIQUE, (empty) // 19: p: typeof(_22) = *mut {l25} i32 // 19: p: l25 = READ | UNIQUE | OFFSET_ADD | OFFSET_SUB, (empty) *&mut (&mut (p)[((j as isize) as usize) ..])[0] = *&(&(&*(p))[(((j - 1 as libc::c_int) as isize) as usize) ..])[0]; // 24: p.offset((j - 1 ... size): typeof(_30) = *mut {l34} i32 // 24: p.offset((j - 1 ... size): l34 = READ | UNIQUE, (empty) // 24: p: typeof(_31) = *mut {l36} i32 // 24: p: l36 = READ | UNIQUE | OFFSET_ADD | OFFSET_SUB, (empty) // 24: p.offset(j as isize): typeof(_37) = *mut {l43} i32 // 24: p.offset(j as isize): l43 = READ | WRITE | UNIQUE, (empty) // 24: p: typeof(_38) = *mut {l45} i32 // 24: p: l45 = READ | WRITE | UNIQUE | OFFSET_ADD | OFFSET_SUB, (empty) j -= 1 } *&mut (&mut (p)[((j as isize) as usize) ..])[0] = tmp; // 29: p.offset(j as isize): typeof(_46) = *mut {l54} i32 // 29: p.offset(j as isize): l54 = READ | WRITE | UNIQUE, (empty) // 29: p: typeof(_47) = *mut {l56} i32 // 29: p: l56 = READ | WRITE | UNIQUE | OFFSET_ADD | OFFSET_SUB, (empty) i += 1 } } ``` This is helpful for debugging, since it means we no longer need to cross-reference line numbers in the debug output with the source code. It's also easy to add more annotations in the future if it would be useful.
- Loading branch information
Showing
7 changed files
with
554 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
use log::warn; | ||
use rustc_middle::ty::TyCtxt; | ||
use rustc_span::{FileName, Span}; | ||
use std::collections::HashMap; | ||
use std::fmt::Display; | ||
|
||
pub struct AnnotationBuffer<'tcx> { | ||
tcx: TyCtxt<'tcx>, | ||
/// Map from `file_idx` to a list of annotations as `(line_number, text)` pairs. | ||
m: HashMap<usize, Vec<(usize, String)>>, | ||
} | ||
|
||
impl<'tcx> AnnotationBuffer<'tcx> { | ||
pub fn new(tcx: TyCtxt<'tcx>) -> AnnotationBuffer<'tcx> { | ||
AnnotationBuffer { | ||
tcx, | ||
m: HashMap::new(), | ||
} | ||
} | ||
|
||
pub fn _clear(&mut self) { | ||
self.m.clear(); | ||
} | ||
|
||
pub fn emit(&mut self, span: Span, msg: impl Display) { | ||
if span.is_dummy() { | ||
// `DUMMY_SP` covers the range `BytePos(0) .. BytePos(0)`. Whichever file happens to | ||
// be added to the `SourceMap` first will be assigned a range starting at `BytePos(0)`, | ||
// so the `SourceFile` lookup below would attach the annotation to that file. Rather | ||
// than letting the annotation be attached to an arbitrary file, we warn and discard | ||
// it. | ||
warn!("discarding annotation on DUMMY_SP: {}", msg); | ||
return; | ||
} | ||
|
||
let sm = self.tcx.sess.source_map(); | ||
|
||
let span = span.source_callsite(); | ||
let pos = span.lo(); | ||
let file_idx = sm.lookup_source_file_idx(pos); | ||
let sf = &sm.files()[file_idx]; | ||
let line = sf.lookup_line(pos).unwrap_or(0); | ||
|
||
let src = sm | ||
.span_to_snippet(span) | ||
.unwrap_or_else(|_| "<error>".into()); | ||
let src = src.split_ascii_whitespace().collect::<Vec<_>>().join(" "); | ||
let (src1, src2, src3) = if src.len() > 20 { | ||
(&src[..15], " ... ", &src[src.len() - 5..]) | ||
} else { | ||
(&src[..], "", "") | ||
}; | ||
self.m.entry(file_idx).or_insert_with(Vec::new).push(( | ||
line, | ||
format!("{}: {}{}{}: {}", line + 1, src1, src2, src3, msg), | ||
)); | ||
} | ||
|
||
pub fn finish(self) -> HashMap<FileName, Vec<(usize, String)>> { | ||
let mut m = HashMap::new(); | ||
let sm = self.tcx.sess.source_map(); | ||
for (file_idx, v) in self.m { | ||
let sf = &sm.files()[file_idx]; | ||
let old = m.insert(sf.name.clone(), v); | ||
assert!( | ||
old.is_none(), | ||
"found multiple SourceFiles named {:?}", | ||
sf.name | ||
); | ||
} | ||
m | ||
} | ||
} |
Oops, something went wrong.