wasmtime_cranelift/debug/transform/
refs.rs

1//! Helper utils for tracking and patching intra unit or section references.
2
3use gimli::write;
4use gimli::{DebugInfoOffset, Reader, UnitHeader, UnitOffset};
5use std::collections::HashMap;
6
7/// Stores compiled unit references: UnitEntryId+DwAt denotes a patch location
8/// and UnitOffset is a location in original DWARF.
9pub struct PendingUnitRefs {
10    refs: Vec<(write::UnitEntryId, gimli::DwAt, UnitOffset)>,
11}
12
13impl PendingUnitRefs {
14    pub fn new() -> Self {
15        Self { refs: Vec::new() }
16    }
17    pub fn insert(&mut self, entry_id: write::UnitEntryId, attr: gimli::DwAt, offset: UnitOffset) {
18        self.refs.push((entry_id, attr, offset));
19    }
20}
21
22/// Stores .debug_info references: UnitEntryId+DwAt denotes a patch location
23/// and DebugInfoOffset is a location in original DWARF.
24pub struct PendingDebugInfoRefs {
25    refs: Vec<(write::UnitEntryId, gimli::DwAt, DebugInfoOffset)>,
26}
27
28impl PendingDebugInfoRefs {
29    pub fn new() -> Self {
30        Self { refs: Vec::new() }
31    }
32    pub fn insert(
33        &mut self,
34        entry_id: write::UnitEntryId,
35        attr: gimli::DwAt,
36        offset: DebugInfoOffset,
37    ) {
38        self.refs.push((entry_id, attr, offset));
39    }
40}
41
42/// Stores map between read and written references of DWARF entries of
43/// a compiled unit.
44pub struct UnitRefsMap {
45    map: HashMap<UnitOffset, write::UnitEntryId>,
46}
47
48impl UnitRefsMap {
49    pub fn new() -> Self {
50        Self {
51            map: HashMap::new(),
52        }
53    }
54    pub fn insert(&mut self, offset: UnitOffset, entry_id: write::UnitEntryId) {
55        self.map.insert(offset, entry_id);
56    }
57    pub fn patch(&self, refs: PendingUnitRefs, comp_unit: &mut write::Unit) {
58        for (die_id, attr_name, offset) in refs.refs {
59            let die = comp_unit.get_mut(die_id);
60            if let Some(unit_id) = self.map.get(&offset) {
61                die.set(attr_name, write::AttributeValue::UnitRef(*unit_id));
62            }
63        }
64    }
65}
66
67/// Stores map between read and written references of DWARF entries of
68/// the entire .debug_info.
69pub struct DebugInfoRefsMap {
70    map: HashMap<DebugInfoOffset, (write::UnitId, write::UnitEntryId)>,
71}
72
73impl DebugInfoRefsMap {
74    pub fn new() -> Self {
75        Self {
76            map: HashMap::new(),
77        }
78    }
79    pub fn insert<R>(&mut self, unit: &UnitHeader<R>, unit_id: write::UnitId, unit_map: UnitRefsMap)
80    where
81        R: Reader<Offset = usize>,
82    {
83        self.map
84            .extend(unit_map.map.into_iter().map(|(off, entry_id)| {
85                let off = off
86                    .to_debug_info_offset(unit)
87                    .expect("should be in debug_info section");
88                (off, (unit_id, entry_id))
89            }));
90    }
91    pub fn patch(
92        &self,
93        refs: impl Iterator<Item = (write::UnitId, PendingDebugInfoRefs)>,
94        units: &mut write::UnitTable,
95    ) {
96        for (id, refs) in refs {
97            let unit = units.get_mut(id);
98            for (die_id, attr_name, offset) in refs.refs {
99                let die = unit.get_mut(die_id);
100                if let Some((id, entry_id)) = self.map.get(&offset) {
101                    die.set(
102                        attr_name,
103                        write::AttributeValue::DebugInfoRef(write::Reference::Entry(
104                            *id, *entry_id,
105                        )),
106                    );
107                }
108            }
109        }
110    }
111}