//! Analysis-side enrichment over [`xenia_cpu::disasm::iter_disasm`]. //! //! Turns a stream of decoder-only [`xenia_cpu::disasm::DisasmItem`]s into a //! stream of [`RichDisasmItem`]s carrying section name + enclosing function + //! label name. The three sinks in [`crate::sinks`] (text, JSON, DuckDB) all //! consume `RichDisasmItem`. use std::collections::HashMap; use xenia_cpu::disasm::DisasmItem; use crate::func::FuncAnalysis; /// `DisasmItem` plus the analysis context (section/function/label). #[derive(Debug, Clone)] pub struct RichDisasmItem<'a> { pub item: DisasmItem, pub section: &'a str, pub function: Option, pub label: Option<&'a str>, } /// Walk one code section, yielding rich items annotated with section name, /// rolling-window enclosing function, and label-at-address. /// /// The `function` field tracks the most recent function-start the iterator /// has crossed — matching the legacy `current_func` behaviour in /// `db.rs::insert_instructions_streaming`. pub fn enrich_section<'a>( image: &'a [u8], image_base: u32, section_name: &'a str, va_start: u32, va_end: u32, func_analysis: &'a FuncAnalysis, labels: &'a HashMap, ) -> impl Iterator> + 'a { let mut current_func: Option = None; xenia_cpu::disasm::iter_disasm(image, image_base, va_start, va_end).map(move |item| { if func_analysis.is_function_start(item.addr) { current_func = Some(item.addr); } let label = labels.get(&item.addr).map(|s| s.as_str()); RichDisasmItem { item, section: section_name, function: current_func, label, } }) }