1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
//! Helper utils for tracking and patching intra unit or section references.

use gimli::write;
use gimli::{DebugInfoOffset, Reader, UnitHeader, UnitOffset};
use std::collections::HashMap;

/// Stores compiled unit references: UnitEntryId+DwAt denotes a patch location
/// and UnitOffset is a location in original DWARF.
pub struct PendingUnitRefs {
    refs: Vec<(write::UnitEntryId, gimli::DwAt, UnitOffset)>,
}

impl PendingUnitRefs {
    pub fn new() -> Self {
        Self { refs: Vec::new() }
    }
    pub fn insert(&mut self, entry_id: write::UnitEntryId, attr: gimli::DwAt, offset: UnitOffset) {
        self.refs.push((entry_id, attr, offset));
    }
}

/// Stores .debug_info references: UnitEntryId+DwAt denotes a patch location
/// and DebugInfoOffset is a location in original DWARF.
pub struct PendingDebugInfoRefs {
    refs: Vec<(write::UnitEntryId, gimli::DwAt, DebugInfoOffset)>,
}

impl PendingDebugInfoRefs {
    pub fn new() -> Self {
        Self { refs: Vec::new() }
    }
    pub fn insert(
        &mut self,
        entry_id: write::UnitEntryId,
        attr: gimli::DwAt,
        offset: DebugInfoOffset,
    ) {
        self.refs.push((entry_id, attr, offset));
    }
}

/// Stores map between read and written references of DWARF entries of
/// a compiled unit.
pub struct UnitRefsMap {
    map: HashMap<UnitOffset, write::UnitEntryId>,
}

impl UnitRefsMap {
    pub fn new() -> Self {
        Self {
            map: HashMap::new(),
        }
    }
    pub fn insert(&mut self, offset: UnitOffset, entry_id: write::UnitEntryId) {
        self.map.insert(offset, entry_id);
    }
    pub fn patch(&self, refs: PendingUnitRefs, comp_unit: &mut write::Unit) {
        for (die_id, attr_name, offset) in refs.refs {
            let die = comp_unit.get_mut(die_id);
            if let Some(unit_id) = self.map.get(&offset) {
                die.set(attr_name, write::AttributeValue::UnitRef(*unit_id));
            }
        }
    }
}

/// Stores map between read and written references of DWARF entries of
/// the entire .debug_info.
pub struct DebugInfoRefsMap {
    map: HashMap<DebugInfoOffset, (write::UnitId, write::UnitEntryId)>,
}

impl DebugInfoRefsMap {
    pub fn new() -> Self {
        Self {
            map: HashMap::new(),
        }
    }
    pub fn insert<R>(&mut self, unit: &UnitHeader<R>, unit_id: write::UnitId, unit_map: UnitRefsMap)
    where
        R: Reader<Offset = usize>,
    {
        self.map
            .extend(unit_map.map.into_iter().map(|(off, entry_id)| {
                let off = off
                    .to_debug_info_offset(unit)
                    .expect("should be in debug_info section");
                (off, (unit_id, entry_id))
            }));
    }
    pub fn patch(
        &self,
        refs: impl Iterator<Item = (write::UnitId, PendingDebugInfoRefs)>,
        units: &mut write::UnitTable,
    ) {
        for (id, refs) in refs {
            let unit = units.get_mut(id);
            for (die_id, attr_name, offset) in refs.refs {
                let die = unit.get_mut(die_id);
                if let Some((id, entry_id)) = self.map.get(&offset) {
                    die.set(
                        attr_name,
                        write::AttributeValue::DebugInfoRef(write::Reference::Entry(
                            *id, *entry_id,
                        )),
                    );
                }
            }
        }
    }
}