Path: blob/main/crates/cranelift/src/debug/gc.rs
1693 views
use crate::debug::Reader;1use crate::debug::transform::AddressTransform;2use gimli::UnitSectionOffset;3use gimli::constants;4use gimli::read;5use std::collections::{HashMap, HashSet};67#[derive(Debug)]8pub struct Dependencies {9edges: HashMap<UnitSectionOffset, HashSet<UnitSectionOffset>>,10roots: HashSet<UnitSectionOffset>,11}1213impl Dependencies {14fn new() -> Dependencies {15Dependencies {16edges: HashMap::new(),17roots: HashSet::new(),18}19}2021fn add_edge(&mut self, a: UnitSectionOffset, b: UnitSectionOffset) {22use std::collections::hash_map::Entry;23match self.edges.entry(a) {24Entry::Occupied(mut o) => {25o.get_mut().insert(b);26}27Entry::Vacant(v) => {28let mut set = HashSet::new();29set.insert(b);30v.insert(set);31}32}33}3435fn add_root(&mut self, root: UnitSectionOffset) {36self.roots.insert(root);37}3839pub fn get_reachable(&self) -> HashSet<UnitSectionOffset> {40let mut reachable = self.roots.clone();41let mut queue = Vec::new();42for i in self.roots.iter() {43if let Some(deps) = self.edges.get(i) {44for j in deps {45if reachable.contains(j) {46continue;47}48reachable.insert(*j);49queue.push(*j);50}51}52}53while let Some(i) = queue.pop() {54if let Some(deps) = self.edges.get(&i) {55for j in deps {56if reachable.contains(j) {57continue;58}59reachable.insert(*j);60queue.push(*j);61}62}63}64reachable65}66}6768pub fn build_dependencies(69dwarf: &read::Dwarf<Reader<'_>>,70at: &AddressTransform,71) -> read::Result<Dependencies> {72let mut deps = Dependencies::new();73let mut units = dwarf.units();74while let Some(unit) = units.next()? {75build_unit_dependencies(unit, dwarf, at, &mut deps)?;76}77Ok(deps)78}7980fn build_unit_dependencies(81header: read::UnitHeader<Reader<'_>>,82dwarf: &read::Dwarf<Reader<'_>>,83at: &AddressTransform,84deps: &mut Dependencies,85) -> read::Result<()> {86let unit = dwarf.unit(header)?;87let mut tree = unit.entries_tree(None)?;88let root = tree.root()?;89build_die_dependencies(root, dwarf, &unit, at, deps)?;90Ok(())91}9293fn has_die_back_edge(die: &read::DebuggingInformationEntry<Reader<'_>>) -> read::Result<bool> {94// DIEs can be broadly divided into three categories:95// 1. Extensions of their parents; effectively attributes: DW_TAG_variable, DW_TAG_member, etc.96// 2. Standalone entities referred to by other DIEs via 'reference' class attributes: types.97// 3. Structural entities that organize how the above relate to each other: namespaces.98// Here, we must make sure to return 'true' for DIEs in the first category since stripping them,99// provided their parent is alive, is always wrong. To be conservatively correct in the face100// of new/vendor tags, we maintain a "(mostly) known good" list of tags of the latter categories.101let result = match die.tag() {102constants::DW_TAG_array_type103| constants::DW_TAG_atomic_type104| constants::DW_TAG_base_type105| constants::DW_TAG_class_type106| constants::DW_TAG_const_type107| constants::DW_TAG_dwarf_procedure108| constants::DW_TAG_entry_point109| constants::DW_TAG_enumeration_type110| constants::DW_TAG_pointer_type111| constants::DW_TAG_ptr_to_member_type112| constants::DW_TAG_reference_type113| constants::DW_TAG_restrict_type114| constants::DW_TAG_rvalue_reference_type115| constants::DW_TAG_string_type116| constants::DW_TAG_structure_type117| constants::DW_TAG_typedef118| constants::DW_TAG_union_type119| constants::DW_TAG_unspecified_type120| constants::DW_TAG_volatile_type121| constants::DW_TAG_coarray_type122| constants::DW_TAG_common_block123| constants::DW_TAG_dynamic_type124| constants::DW_TAG_file_type125| constants::DW_TAG_immutable_type126| constants::DW_TAG_interface_type127| constants::DW_TAG_set_type128| constants::DW_TAG_shared_type129| constants::DW_TAG_subroutine_type130| constants::DW_TAG_packed_type131| constants::DW_TAG_template_alias132| constants::DW_TAG_namelist133| constants::DW_TAG_namespace134| constants::DW_TAG_imported_unit135| constants::DW_TAG_imported_declaration136| constants::DW_TAG_imported_module137| constants::DW_TAG_module => false,138constants::DW_TAG_subprogram => die.attr(constants::DW_AT_declaration)?.is_some(),139_ => true,140};141Ok(result)142}143144fn has_valid_code_range(145die: &read::DebuggingInformationEntry<Reader<'_>>,146dwarf: &read::Dwarf<Reader<'_>>,147unit: &read::Unit<Reader<'_>>,148at: &AddressTransform,149) -> read::Result<bool> {150match die.tag() {151constants::DW_TAG_subprogram => {152if let Some(ranges_attr) = die.attr_value(constants::DW_AT_ranges)? {153let offset = match ranges_attr {154read::AttributeValue::RangeListsRef(val) => {155dwarf.ranges_offset_from_raw(unit, val)156}157read::AttributeValue::DebugRngListsIndex(index) => {158dwarf.ranges_offset(unit, index)?159}160_ => return Ok(false),161};162let mut has_valid_base = if let Some(read::AttributeValue::Addr(low_pc)) =163die.attr_value(constants::DW_AT_low_pc)?164{165Some(at.can_translate_address(low_pc))166} else {167None168};169let mut it = dwarf.ranges.raw_ranges(offset, unit.encoding())?;170while let Some(range) = it.next()? {171// If at least one of the range addresses can be converted,172// declaring code range as valid.173match range {174read::RawRngListEntry::AddressOrOffsetPair { .. }175if has_valid_base.is_some() =>176{177if has_valid_base.unwrap() {178return Ok(true);179}180}181read::RawRngListEntry::StartEnd { begin, .. }182| read::RawRngListEntry::StartLength { begin, .. }183| read::RawRngListEntry::AddressOrOffsetPair { begin, .. } => {184if at.can_translate_address(begin) {185return Ok(true);186}187}188read::RawRngListEntry::StartxEndx { begin, .. }189| read::RawRngListEntry::StartxLength { begin, .. } => {190let addr = dwarf.address(unit, begin)?;191if at.can_translate_address(addr) {192return Ok(true);193}194}195read::RawRngListEntry::BaseAddress { addr } => {196has_valid_base = Some(at.can_translate_address(addr));197}198read::RawRngListEntry::BaseAddressx { addr } => {199let addr = dwarf.address(unit, addr)?;200has_valid_base = Some(at.can_translate_address(addr));201}202read::RawRngListEntry::OffsetPair { .. } => (),203}204}205return Ok(false);206} else if let Some(low_pc) = die.attr_value(constants::DW_AT_low_pc)? {207if let read::AttributeValue::Addr(a) = low_pc {208return Ok(at.can_translate_address(a));209} else if let read::AttributeValue::DebugAddrIndex(i) = low_pc {210let a = dwarf.debug_addr.get_address(4, unit.addr_base, i)?;211return Ok(at.can_translate_address(a));212}213}214}215_ => (),216}217Ok(false)218}219220fn build_die_dependencies(221die: read::EntriesTreeNode<Reader<'_>>,222dwarf: &read::Dwarf<Reader<'_>>,223unit: &read::Unit<Reader<'_>>,224at: &AddressTransform,225deps: &mut Dependencies,226) -> read::Result<()> {227let entry = die.entry();228let offset = entry.offset().to_unit_section_offset(unit);229let mut attrs = entry.attrs();230while let Some(attr) = attrs.next()? {231build_attr_dependencies(&attr, offset, dwarf, unit, at, deps)?;232}233234let mut children = die.children();235while let Some(child) = children.next()? {236let child_entry = child.entry();237let child_offset = child_entry.offset().to_unit_section_offset(unit);238deps.add_edge(child_offset, offset);239if has_die_back_edge(child_entry)? {240deps.add_edge(offset, child_offset);241}242if has_valid_code_range(child_entry, dwarf, unit, at)? {243deps.add_root(child_offset);244}245build_die_dependencies(child, dwarf, unit, at, deps)?;246}247Ok(())248}249250fn build_attr_dependencies(251attr: &read::Attribute<Reader<'_>>,252offset: UnitSectionOffset,253_dwarf: &read::Dwarf<Reader<'_>>,254unit: &read::Unit<Reader<'_>>,255_at: &AddressTransform,256deps: &mut Dependencies,257) -> read::Result<()> {258match attr.value() {259read::AttributeValue::UnitRef(val) => {260let ref_offset = val.to_unit_section_offset(unit);261deps.add_edge(offset, ref_offset);262}263read::AttributeValue::DebugInfoRef(val) => {264let ref_offset = UnitSectionOffset::DebugInfoOffset(val);265deps.add_edge(offset, ref_offset);266}267_ => (),268}269Ok(())270}271272273