wasmtime_cranelift/debug/transform/
mod.rs

1use self::refs::DebugInfoRefsMap;
2use self::simulate::generate_simulated_dwarf;
3use self::unit::clone_unit;
4use crate::debug::gc::build_dependencies;
5use crate::debug::ModuleMemoryOffset;
6use crate::CompiledFunctions;
7use anyhow::Error;
8use cranelift_codegen::isa::TargetIsa;
9use gimli::{
10    write, DebugAddr, DebugLine, DebugLineStr, DebugStr, DebugStrOffsets, LocationLists,
11    RangeLists, UnitSectionOffset,
12};
13use std::collections::HashSet;
14use thiserror::Error;
15use wasmtime_environ::DebugInfoData;
16
17pub use address_transform::AddressTransform;
18
19mod address_transform;
20mod attr;
21mod expression;
22mod line_program;
23mod range_info_builder;
24mod refs;
25mod simulate;
26mod unit;
27mod utils;
28
29pub(crate) trait Reader: gimli::Reader<Offset = usize> {}
30
31impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where Endian: gimli::Endianity {}
32
33#[derive(Error, Debug)]
34#[error("Debug info transform error: {0}")]
35pub struct TransformError(&'static str);
36
37pub(crate) struct DebugInputContext<'a, R>
38where
39    R: Reader,
40{
41    debug_str: &'a DebugStr<R>,
42    debug_str_offsets: &'a DebugStrOffsets<R>,
43    debug_line_str: &'a DebugLineStr<R>,
44    debug_line: &'a DebugLine<R>,
45    debug_addr: &'a DebugAddr<R>,
46    rnglists: &'a RangeLists<R>,
47    loclists: &'a LocationLists<R>,
48    reachable: &'a HashSet<UnitSectionOffset>,
49}
50
51pub fn transform_dwarf(
52    isa: &dyn TargetIsa,
53    di: &DebugInfoData,
54    funcs: &CompiledFunctions,
55    memory_offset: &ModuleMemoryOffset,
56) -> Result<write::Dwarf, Error> {
57    let addr_tr = AddressTransform::new(funcs, &di.wasm_file);
58    let reachable = build_dependencies(&di.dwarf, &addr_tr)?.get_reachable();
59
60    let context = DebugInputContext {
61        debug_str: &di.dwarf.debug_str,
62        debug_str_offsets: &di.dwarf.debug_str_offsets,
63        debug_line_str: &di.dwarf.debug_line_str,
64        debug_line: &di.dwarf.debug_line,
65        debug_addr: &di.dwarf.debug_addr,
66        rnglists: &di.dwarf.ranges,
67        loclists: &di.dwarf.locations,
68        reachable: &reachable,
69    };
70
71    let out_encoding = gimli::Encoding {
72        format: gimli::Format::Dwarf32,
73        // TODO: this should be configurable
74        version: 4,
75        address_size: isa.pointer_bytes(),
76    };
77
78    let mut out_strings = write::StringTable::default();
79    let mut out_units = write::UnitTable::default();
80
81    let out_line_strings = write::LineStringTable::default();
82    let mut pending_di_refs = Vec::new();
83    let mut di_ref_map = DebugInfoRefsMap::new();
84
85    let mut translated = HashSet::new();
86    let mut iter = di.dwarf.debug_info.units();
87    while let Some(header) = iter.next().unwrap_or(None) {
88        let unit = di.dwarf.unit(header)?;
89        if let Some((id, ref_map, pending_refs)) = clone_unit(
90            &di.dwarf,
91            unit,
92            &context,
93            &addr_tr,
94            funcs,
95            memory_offset,
96            out_encoding,
97            &mut out_units,
98            &mut out_strings,
99            &mut translated,
100            isa,
101        )? {
102            di_ref_map.insert(&header, id, ref_map);
103            pending_di_refs.push((id, pending_refs));
104        }
105    }
106    di_ref_map.patch(pending_di_refs.into_iter(), &mut out_units);
107
108    generate_simulated_dwarf(
109        &addr_tr,
110        di,
111        memory_offset,
112        funcs,
113        &translated,
114        out_encoding,
115        &mut out_units,
116        &mut out_strings,
117        isa,
118    )?;
119
120    Ok(write::Dwarf {
121        units: out_units,
122        line_programs: vec![],
123        line_strings: out_line_strings,
124        strings: out_strings,
125    })
126}