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
112
113
114
115
116
117
118
119
120
121
122
use yaxpeax_arch::{Arch, LengthedInstruction};
use yaxpeax_pic17::PIC17;
use analyses::control_flow::Effect;
use arch::pic17::cpu::try_debank;
use arch::pic17::StateUpdate;
use arch::pic17;
use ContextRead;

pub fn all_instruction_analyses(
    instr: &<PIC17 as Arch>::Instruction,
    address: <PIC17 as Arch>::Address,
    effect: &Effect<<PIC17 as Arch>::Address>,
    ctxs: &pic17::MergedContextTable
) -> Vec<(<PIC17 as Arch>::Address, StateUpdate)> {
    let mut results = compute_bit_name(instr, address, effect, ctxs);
    results.extend(collect_function_hint(instr, address, effect, ctxs));
    results.extend(compute_next_state(instr, address, effect, ctxs));
    results
}

pub fn compute_next_state(
    instr: &<PIC17 as Arch>::Instruction,
    address: <PIC17 as Arch>::Address,
    effect: &Effect<<PIC17 as Arch>::Address>,
    ctxs: &pic17::MergedContextTable
) -> Vec<(<PIC17 as Arch>::Address, StateUpdate)> {
    // this exposes a bug. if the current instruction ends a basic block
    // we might compute some state applied to the next instruction eg after the
    // end of this block.
    //
    // this is permitted because blocks are Copy and the version that's updated
    // is in the cfg where we have a potentially out of date one.
    let ctx = pic17::compute_state(&instr, &ctxs.at(&address));

    if !effect.is_stop() {
        vec![(address + instr.len(), pic17::StateUpdate::FullContext(ctx))]
    } else {
        vec![]
    }
}

pub fn collect_function_hint(
    _instr: &<PIC17 as Arch>::Instruction,
    _address: <PIC17 as Arch>::Address,
    _effect: &Effect<<PIC17 as Arch>::Address>,
    _ctxs: &pic17::MergedContextTable
) -> Vec<(<PIC17 as Arch>::Address, StateUpdate)> {
    unimplemented!("function hints for pic17 analyses");
    /*
    if instr.is_call() {
        match effect.dest {
            Some(Target::Relative(rel)) => {
                // TODO: have a high level program info
                // declare functions on it.
                // program_model.declare_function(
                // instead.....
                let addr = address + rel;
                if !function_table.contains_key(&addr) {
                    vec![(addr, pic17::Function::new(format!("fn_{:04x}", addr), vec![]))]
                }
            },
            Some(Target::Absolute(dest)) => {
                // TODO: have a high level program info
                // declare functions on it.
                // program_model.declare_function(
                // instead.....
                let addr = dest;
                if !function_table.contains_key(&addr) {
                    vec![(addr, pic17::Function::new(format!("fn_{:04x}", addr), vec![]))]
                }
            }
            _ => {
                panic!("What *is* a call to an unknown or multiple dest?");
            }
        }
    }
    */
}

pub fn compute_bit_name(
    instr: &<PIC17 as Arch>::Instruction,
    address: <PIC17 as Arch>::Address,
    _effect: &Effect<<PIC17 as Arch>::Address>,
    ctxs: &pic17::MergedContextTable
) -> Vec<(<PIC17 as Arch>::Address, StateUpdate)> {
    let comment = match instr.opcode {
        yaxpeax_pic17::Opcode::BTG |
        yaxpeax_pic17::Opcode::BSF |
        yaxpeax_pic17::Opcode::BCF |
        yaxpeax_pic17::Opcode::BTFSS |
        yaxpeax_pic17::Opcode::BTFSC => {
            let bit_num = match instr.operands[1] {
                yaxpeax_pic17::Operand::ImmediateU8(bit_num) => bit_num,
                _ => unreachable!()
            };

            let file_value = match instr.operands[0] {
                yaxpeax_pic17::Operand::File(f) => f,
                _ => unreachable!()
            };

            match try_debank(file_value, Some(&ctxs.at(&address))) {
                Some(file) => {
                    pic17::bit_name(file, bit_num)
                },
                None => None
            }
        },
        _ => {
            None
        }
    };

    match comment {
        Some(comment) => {
            vec![(address + instr.len(), StateUpdate::ComputedComment(comment.to_owned()))]
        },
        None => {
            vec![]
        }
    }
}