charm 0.0.1

ARM assembler & disassembler generated from the ARM exploration tools.
Documentation
use std::{
    ffi::{CString, c_char},
    ptr::*,
};

use llvm_sys::disassembler::*;
use llvm_sys::target::*;

mod core;

#[derive(Debug)]
struct TestFieldState {
    inverse: bool,
    width: u32,
    index: u32,
    current: Option<u32>,
}

impl TestFieldState {
    pub fn new(width: u32) -> Self {
        Self {
            inverse: false,
            width,
            index: 0,
            current: None,
        }
    }

    pub fn reset(&mut self) {
        self.inverse = false;
        self.index = 0;
        self.current = None;
    }
}

impl Iterator for TestFieldState {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        if self.width <= 2 {
            if self.index == 1 << self.width {
                return None;
            }
            self.current = Some(self.index);
        } else {
            if self.index >= self.width + 1 {
                if self.inverse {
                    return None;
                }
                self.inverse = true;
                self.index = 0;
            }
            if self.inverse {
                let value = 2_u32.pow(self.width - self.index) >> 1;
                self.current = Some(!value & (2_u32.pow(self.width) - 1));
            } else {
                let value = 2_u32.pow(self.index) >> 1;
                self.current = Some(value);
            }
        }
        self.index += 1;
        self.current
    }
}

struct TestIterator<const N: usize> {
    states: [TestFieldState; N],
}

impl<const N: usize> TestIterator<N> {
    fn new(widths: &[u32; N]) -> Self {
        let states = widths
            .iter()
            .map(|f| TestFieldState::new(*f))
            .collect::<Vec<TestFieldState>>()
            .try_into()
            .unwrap();
        Self { states }
    }
}

impl<const N: usize> Iterator for TestIterator<N> {
    type Item = [u32; N];

    fn next(&mut self) -> Option<Self::Item> {
        if N == 0 {
            return None;
        }
        let mut values = [0; N];
        let mut next = true;
        for (i, (s, v)) in self.states.iter_mut().zip(values.iter_mut()).enumerate() {
            if next {
                match s.next() {
                    None => {
                        if i == N - 1 {
                            return None;
                        } else {
                            s.reset();
                            *v = s.next().unwrap();
                        }
                    }
                    Some(x) => {
                        *v = x;
                        next = false;
                    }
                }
            } else {
                match s.current {
                    None => *v = s.next().unwrap(),
                    Some(x) => *v = x,
                }
            }
        }
        Some(values)
    }
}

pub fn llvm_create_disassembler(
    triple: &str,
    cpu: &str,
    features: &str,
) -> Option<LLVMDisasmContextRef> {
    unsafe {
        // LLVMInitializeARMTarget();
        // LLVMInitializeARMTargetInfo();
        // LLVMInitializeARMAsmPrinter();
        // LLVMInitializeARMAsmParser();
        // LLVMInitializeARMDisassembler();
        // LLVMInitializeARMTargetMC();

        LLVMInitializeARMTargetInfo();
        LLVMInitializeARMTargetMC();
        LLVMInitializeARMDisassembler();
        LLVMInitializeAArch64TargetInfo();
        LLVMInitializeAArch64TargetMC();
        LLVMInitializeAArch64Disassembler();

        let triple = CString::new(triple).unwrap();
        let cpu = CString::new(cpu).unwrap();
        let features = CString::new(features).unwrap();
        // let d = LLVMCreateDisasm(
        //     triple.as_ptr() as *const i8,
        //     null_mut(),
        //     0,
        //     None,
        //     None,
        // );
        let d = LLVMCreateDisasmCPUFeatures(
            triple.as_ptr(),
            cpu.as_ptr(),
            features.as_ptr(),
            null_mut(),
            0,
            None,
            None,
        );

        if d.is_null() { None } else { Some(d) }
    }
}

pub fn llvm_dispose_disassembler(d: LLVMDisasmContextRef) {
    unsafe {
        LLVMDisasmDispose(d);
    }
}

pub fn llvm_disassemble(d: LLVMDisasmContextRef, insn: &mut [u8], address: u64) -> Vec<String> {
    let mut outdisas = [0u8; 0x100];
    let mut outinsn = Vec::new();
    let mut offset = 0;
    let mut address = address;
    unsafe {
        loop {
            let l = LLVMDisasmInstruction(
                d,
                insn[offset..].as_mut_ptr() as *mut u8,
                (insn.len() - offset) as u64,
                address,
                outdisas.as_mut_ptr() as *mut c_char,
                0x100,
            );
            let null_byte_pos = outdisas.iter().position(|&b| b == 0).unwrap();
            if l == 0 {
                break;
            }
            outinsn.push(
                String::from_utf8(outdisas[1..null_byte_pos].to_vec())
                    .unwrap()
                    .to_string()
                    .replace('\t', " "),
            );
            address += l as u64;
            offset += l as usize;
        }
    }
    outinsn
}