From 19392d05b04fe899e106ff2ecccb1419a434bd95 Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Mon, 13 Feb 2023 16:17:17 -0800 Subject: [PATCH] Add debug-loc info --- src/frontend.rs | 46 +++++++++++++++++++++++++++++++++++++++------- src/ir/debug.rs | 47 +++++++++++++++++++++++++++++++---------------- src/ir/display.rs | 17 ++++++++++++++--- src/ir/func.rs | 4 ++++ 4 files changed, 88 insertions(+), 26 deletions(-) diff --git a/src/frontend.rs b/src/frontend.rs index ee6062f..891dcff 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -357,6 +357,33 @@ fn handle_payload<'a>( 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>( module: &'a Module, my_sig: Signature, @@ -364,6 +391,9 @@ pub(crate) fn parse_body<'a>( ) -> Result { let mut ret: FunctionBody = FunctionBody::default(); + let start_offset = body.range().start; + let mut debug_locs = DebugLocReader::new(module, start_offset); + for ¶m in &module.signatures[my_sig].params[..] { ret.locals.push(param.into()); } @@ -409,17 +439,18 @@ pub(crate) fn parse_body<'a>( } let ops = body.get_operators_reader()?; - for op in ops.into_iter() { - let op = op?; + for item in ops.into_iter_with_offsets() { + let (op, offset) = item?; + let loc = debug_locs.get_loc(offset); if builder.reachable { - builder.handle_op(op)?; + builder.handle_op(op, loc)?; } else { builder.handle_op_unreachable(op)?; } } if builder.reachable { - builder.handle_op(wasmparser::Operator::Return)?; + builder.handle_op(wasmparser::Operator::Return, SourceLoc::invalid())?; } 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!("op_stack = {:?}", self.op_stack); trace!("ctrl_stack = {:?}", self.ctrl_stack); @@ -1089,7 +1120,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { | wasmparser::Operator::TableSet { .. } | wasmparser::Operator::TableGrow { .. } | wasmparser::Operator::TableSize { .. } => { - self.emit(Operator::try_from(&op).unwrap())? + self.emit(Operator::try_from(&op).unwrap(), loc)? } 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 outputs = op_outputs(self.module, &self.op_stack[..], &op)?; @@ -1641,6 +1672,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { if self.reachable { self.body.append_to_block(self.cur_block, value); } + self.body.source_locs[value] = loc; if n_outputs == 1 { let output_ty = outputs[0]; diff --git a/src/ir/debug.rs b/src/ir/debug.rs index 2589d97..969de8c 100644 --- a/src/ir/debug.rs +++ b/src/ir/debug.rs @@ -5,23 +5,24 @@ use crate::entity::EntityVec; use addr2line::gimli; use std::collections::hash_map::Entry as HashEntry; use std::collections::HashMap; +use std::convert::TryFrom; declare_entity!(SourceFile, "file"); declare_entity!(SourceLoc, "loc"); #[derive(Clone, Debug, Default)] pub struct Debug { - source_files: EntityVec, + pub source_files: EntityVec, source_file_dedup: HashMap, - source_locs: EntityVec, + pub source_locs: EntityVec, source_loc_dedup: HashMap, } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SourceLocData { - file: SourceFile, - line: u32, - col: u32, + pub file: SourceFile, + pub line: u32, + pub col: u32, } impl Debug { @@ -60,25 +61,39 @@ impl DebugMap { let mut tuples = vec![]; 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 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(); - println!("tuples:"); let mut last = 0; - for &(start, len, loc) in &tuples { - if start < last { - println!(" WARNING: OVERLAP"); + tuples.retain(|&(start, len, _)| { + let retain = start >= last; + if retain { + last = start + len; } - last = start + len; - println!(" {:x} - {:x}: {}", start, start + len, loc); - } - println!("files: {:?}", debug.source_files); - println!("locs: {:?}", debug.source_locs); + retain + }); 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..] + } } diff --git a/src/ir/display.rs b/src/ir/display.rs index c717ba0..6a8dbf1 100644 --- a/src/ir/display.rs +++ b/src/ir/display.rs @@ -78,7 +78,7 @@ impl<'a> Display for FunctionBodyDisplay<'a> { .iter() .map(|(ty, val)| format!("{}: {}", val, ty)) .collect::>(); - writeln!(f, "{} {}({}):", self.1, block_id, block_params.join(", "))?; + writeln!(f, "{} {}({}):", self.1, block_id, block_params.join(", "),)?; writeln!( f, "{} # preds: {}", @@ -116,12 +116,13 @@ impl<'a> Display for FunctionBodyDisplay<'a> { let tys = tys.iter().map(|&ty| format!("{}", ty)).collect::>(); writeln!( f, - "{} {} = {} {} # {}", + "{} {} = {} {} # {} @{}", self.1, inst, op, args.join(", "), - tys.join(", ") + tys.join(", "), + self.0.source_locs[inst], )?; } 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, "}}")?; Ok(()) } diff --git a/src/ir/func.rs b/src/ir/func.rs index cf76637..5aa0be4 100644 --- a/src/ir/func.rs +++ b/src/ir/func.rs @@ -2,6 +2,7 @@ use super::{Block, FunctionBodyDisplay, Local, Module, Signature, Type, Value, V use crate::cfg::CFGInfo; use crate::entity::{EntityRef, EntityVec, PerEntity}; use crate::frontend::parse_body; +use crate::ir::SourceLoc; use anyhow::Result; #[derive(Clone, Debug)] @@ -99,6 +100,8 @@ pub struct FunctionBody { pub value_blocks: PerEntity, /// Wasm locals that values correspond to, if any. pub value_locals: PerEntity>, + /// Debug source locations of each value. + pub source_locs: PerEntity, } impl FunctionBody { @@ -124,6 +127,7 @@ impl FunctionBody { values, value_blocks, value_locals: PerEntity::default(), + source_locs: PerEntity::default(), } }