univdreams 0.4.0

Byte-identical binary <-> source round-tripping: binary formats, multi-arch decode/encode, a .ud decompiler/compiler, and an x86 emulator with Win16/Win32/Linux hosts.
Documentation
//! AArch64 function-body builder.
//!
//! v0 mirrors the shape of `build_function` for x86 but is much
//! simpler: the aarch64 backend doesn't yet do prologue/epilogue
//! lifting, call-site analysis, or if/else grouping. Each decoded
//! instruction emits one `@asm` line whose text comes from
//! [`crate::arch::aarch64::format_text`] (a placeholder that names
//! recognised flow-control mnemonics and falls back to
//! `<arm64 0xXXXXXXXX>` for everything else).
//!
//! Direct calls and unconditional branches still get the standard
//! `// -> name` annotations when the target is a known function —
//! that's format-agnostic and uses `name_at` only.

use std::collections::HashMap;

use crate::arch::aarch64::{DecodedInsn, InsnKind, format_text};
use crate::ast::{FnDecl, Stmt};
use crate::ir::Function;

/// Build a `FnDecl` from a lifted AArch64 function.
#[must_use]
pub fn build_function(f: &Function<DecodedInsn>, name_at: &HashMap<u64, String>) -> FnDecl {
    let mut body = Vec::new();
    for block in &f.blocks {
        for insn in &block.insns {
            body.push(Stmt::asm(format_text(insn), insn.bytes.to_vec()));
            if let Some(annotation) = call_or_branch_annotation(insn, name_at) {
                body.push(Stmt::Comment(annotation));
            }
        }
    }
    FnDecl {
        addr: Some(f.addr.0),
        name: f.name.clone(),
        attrs: Vec::new(),
        locals: Vec::new(),
        signature: None,
        body,
    }
}

/// Format-agnostic annotation for direct branches/calls whose
/// target is a known function.
fn call_or_branch_annotation(insn: &DecodedInsn, name_at: &HashMap<u64, String>) -> Option<String> {
    match insn.kind {
        InsnKind::BranchLink { target } => name_at.get(&target).map(|n| format!("-> {n}")),
        InsnKind::BranchDirect { target } => name_at.get(&target).map(|n| format!("-> {n}")),
        _ => None,
    }
}