Add debug-loc info

This commit is contained in:
Chris Fallin 2023-02-13 16:17:17 -08:00
parent aac46663f0
commit 19392d05b0
4 changed files with 88 additions and 26 deletions

View file

@ -357,6 +357,33 @@ fn handle_payload<'a>(
Ok(()) Ok(())
} }
struct DebugLocReader<'a> {
locs: &'a [(u32, u32, SourceLoc)],
}
impl<'a> DebugLocReader<'a> {
fn new(module: &'a Module, offset: usize) -> Self {
DebugLocReader {
locs: module.debug_map.locs_from_offset(offset),
}
}
fn get_loc(&mut self, offset: usize) -> SourceLoc {
let offset = u32::try_from(offset).unwrap();
while self.locs.len() > 0 {
let (start, len, loc) = self.locs[0];
if offset < start {
break;
}
if offset > (start + len) {
self.locs = &self.locs[1..];
}
return loc;
}
SourceLoc::invalid()
}
}
pub(crate) fn parse_body<'a>( pub(crate) fn parse_body<'a>(
module: &'a Module, module: &'a Module,
my_sig: Signature, my_sig: Signature,
@ -364,6 +391,9 @@ pub(crate) fn parse_body<'a>(
) -> Result<FunctionBody> { ) -> Result<FunctionBody> {
let mut ret: FunctionBody = FunctionBody::default(); let mut ret: FunctionBody = FunctionBody::default();
let start_offset = body.range().start;
let mut debug_locs = DebugLocReader::new(module, start_offset);
for &param in &module.signatures[my_sig].params[..] { for &param in &module.signatures[my_sig].params[..] {
ret.locals.push(param.into()); ret.locals.push(param.into());
} }
@ -409,17 +439,18 @@ pub(crate) fn parse_body<'a>(
} }
let ops = body.get_operators_reader()?; let ops = body.get_operators_reader()?;
for op in ops.into_iter() { for item in ops.into_iter_with_offsets() {
let op = op?; let (op, offset) = item?;
let loc = debug_locs.get_loc(offset);
if builder.reachable { if builder.reachable {
builder.handle_op(op)?; builder.handle_op(op, loc)?;
} else { } else {
builder.handle_op_unreachable(op)?; builder.handle_op_unreachable(op)?;
} }
} }
if builder.reachable { if builder.reachable {
builder.handle_op(wasmparser::Operator::Return)?; builder.handle_op(wasmparser::Operator::Return, SourceLoc::invalid())?;
} }
for block in builder.body.blocks.iter() { for block in builder.body.blocks.iter() {
@ -878,7 +909,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
} }
} }
fn handle_op(&mut self, op: wasmparser::Operator<'a>) -> Result<()> { fn handle_op(&mut self, op: wasmparser::Operator<'a>, loc: SourceLoc) -> Result<()> {
trace!("handle_op: {:?}", op); trace!("handle_op: {:?}", op);
trace!("op_stack = {:?}", self.op_stack); trace!("op_stack = {:?}", self.op_stack);
trace!("ctrl_stack = {:?}", self.ctrl_stack); trace!("ctrl_stack = {:?}", self.ctrl_stack);
@ -1089,7 +1120,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
| wasmparser::Operator::TableSet { .. } | wasmparser::Operator::TableSet { .. }
| wasmparser::Operator::TableGrow { .. } | wasmparser::Operator::TableGrow { .. }
| wasmparser::Operator::TableSize { .. } => { | wasmparser::Operator::TableSize { .. } => {
self.emit(Operator::try_from(&op).unwrap())? self.emit(Operator::try_from(&op).unwrap(), loc)?
} }
wasmparser::Operator::Nop => {} wasmparser::Operator::Nop => {}
@ -1610,7 +1641,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
} }
} }
fn emit(&mut self, op: Operator) -> Result<()> { fn emit(&mut self, op: Operator, loc: SourceLoc) -> Result<()> {
let inputs = op_inputs(self.module, &self.op_stack[..], &op)?; let inputs = op_inputs(self.module, &self.op_stack[..], &op)?;
let outputs = op_outputs(self.module, &self.op_stack[..], &op)?; let outputs = op_outputs(self.module, &self.op_stack[..], &op)?;
@ -1641,6 +1672,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
if self.reachable { if self.reachable {
self.body.append_to_block(self.cur_block, value); self.body.append_to_block(self.cur_block, value);
} }
self.body.source_locs[value] = loc;
if n_outputs == 1 { if n_outputs == 1 {
let output_ty = outputs[0]; let output_ty = outputs[0];

View file

@ -5,23 +5,24 @@ use crate::entity::EntityVec;
use addr2line::gimli; use addr2line::gimli;
use std::collections::hash_map::Entry as HashEntry; use std::collections::hash_map::Entry as HashEntry;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryFrom;
declare_entity!(SourceFile, "file"); declare_entity!(SourceFile, "file");
declare_entity!(SourceLoc, "loc"); declare_entity!(SourceLoc, "loc");
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct Debug { pub struct Debug {
source_files: EntityVec<SourceFile, String>, pub source_files: EntityVec<SourceFile, String>,
source_file_dedup: HashMap<String, SourceFile>, source_file_dedup: HashMap<String, SourceFile>,
source_locs: EntityVec<SourceLoc, SourceLocData>, pub source_locs: EntityVec<SourceLoc, SourceLocData>,
source_loc_dedup: HashMap<SourceLocData, SourceLoc>, source_loc_dedup: HashMap<SourceLocData, SourceLoc>,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SourceLocData { pub struct SourceLocData {
file: SourceFile, pub file: SourceFile,
line: u32, pub line: u32,
col: u32, pub col: u32,
} }
impl Debug { impl Debug {
@ -60,25 +61,39 @@ impl DebugMap {
let mut tuples = vec![]; let mut tuples = vec![];
let mut locs = ctx.find_location_range(0, u64::MAX).unwrap(); let mut locs = ctx.find_location_range(0, u64::MAX).unwrap();
while let Some((start, end, loc)) = locs.next() { while let Some((start, len, loc)) = locs.next() {
let file = debug.intern_file(loc.file.unwrap_or("")); let file = debug.intern_file(loc.file.unwrap_or(""));
let loc = debug.intern_loc(file, loc.line.unwrap_or(0), loc.column.unwrap_or(0)); let loc = debug.intern_loc(file, loc.line.unwrap_or(0), loc.column.unwrap_or(0));
tuples.push((start as u32, end as u32, loc)); tuples.push((start as u32, len as u32, loc));
} }
tuples.sort(); tuples.sort();
println!("tuples:");
let mut last = 0; let mut last = 0;
for &(start, len, loc) in &tuples { tuples.retain(|&(start, len, _)| {
if start < last { let retain = start >= last;
println!(" WARNING: OVERLAP"); if retain {
}
last = start + len; last = start + len;
println!(" {:x} - {:x}: {}", start, start + len, loc);
} }
println!("files: {:?}", debug.source_files); retain
println!("locs: {:?}", debug.source_locs); });
Ok(DebugMap { tuples }) Ok(DebugMap { tuples })
} }
pub(crate) fn locs_from_offset<'a>(&'a self, offset: usize) -> &'a [(u32, u32, SourceLoc)] {
let offset = u32::try_from(offset).unwrap();
let start = match self.tuples.binary_search_by(|&(start, len, _)| {
if offset < start {
std::cmp::Ordering::Greater
} else if offset >= (start + len) {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Equal
}
}) {
Ok(idx) => idx,
Err(first_after) => first_after,
};
&self.tuples[start..]
}
} }

View file

@ -78,7 +78,7 @@ impl<'a> Display for FunctionBodyDisplay<'a> {
.iter() .iter()
.map(|(ty, val)| format!("{}: {}", val, ty)) .map(|(ty, val)| format!("{}: {}", val, ty))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
writeln!(f, "{} {}({}):", self.1, block_id, block_params.join(", "))?; writeln!(f, "{} {}({}):", self.1, block_id, block_params.join(", "),)?;
writeln!( writeln!(
f, f,
"{} # preds: {}", "{} # preds: {}",
@ -116,12 +116,13 @@ impl<'a> Display for FunctionBodyDisplay<'a> {
let tys = tys.iter().map(|&ty| format!("{}", ty)).collect::<Vec<_>>(); let tys = tys.iter().map(|&ty| format!("{}", ty)).collect::<Vec<_>>();
writeln!( writeln!(
f, f,
"{} {} = {} {} # {}", "{} {} = {} {} # {} @{}",
self.1, self.1,
inst, inst,
op, op,
args.join(", "), args.join(", "),
tys.join(", ") tys.join(", "),
self.0.source_locs[inst],
)?; )?;
} }
ValueDef::PickOutput(val, idx, ty) => { ValueDef::PickOutput(val, idx, ty) => {
@ -243,6 +244,16 @@ impl<'a> Display for ModuleDisplay<'a> {
} }
} }
} }
for (loc, loc_data) in self.0.debug.source_locs.entries() {
writeln!(
f,
" {} = {} line {} column {}",
loc, loc_data.file, loc_data.line, loc_data.col
)?;
}
for (file, file_name) in self.0.debug.source_files.entries() {
writeln!(f, " {} = \"{}\"", file, file_name)?;
}
writeln!(f, "}}")?; writeln!(f, "}}")?;
Ok(()) Ok(())
} }

View file

@ -2,6 +2,7 @@ use super::{Block, FunctionBodyDisplay, Local, Module, Signature, Type, Value, V
use crate::cfg::CFGInfo; use crate::cfg::CFGInfo;
use crate::entity::{EntityRef, EntityVec, PerEntity}; use crate::entity::{EntityRef, EntityVec, PerEntity};
use crate::frontend::parse_body; use crate::frontend::parse_body;
use crate::ir::SourceLoc;
use anyhow::Result; use anyhow::Result;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -99,6 +100,8 @@ pub struct FunctionBody {
pub value_blocks: PerEntity<Value, Block>, pub value_blocks: PerEntity<Value, Block>,
/// Wasm locals that values correspond to, if any. /// Wasm locals that values correspond to, if any.
pub value_locals: PerEntity<Value, Option<Local>>, pub value_locals: PerEntity<Value, Option<Local>>,
/// Debug source locations of each value.
pub source_locs: PerEntity<Value, SourceLoc>,
} }
impl FunctionBody { impl FunctionBody {
@ -124,6 +127,7 @@ impl FunctionBody {
values, values,
value_blocks, value_blocks,
value_locals: PerEntity::default(), value_locals: PerEntity::default(),
source_locs: PerEntity::default(),
} }
} }