Add debug-loc info
This commit is contained in:
parent
aac46663f0
commit
19392d05b0
|
@ -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 ¶m in &module.signatures[my_sig].params[..] {
|
for ¶m 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];
|
||||||
|
|
|
@ -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..]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue