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
use std::borrow::Cow;

use compiler::{Opdata, FormatStringIterator};
use x64data::flags::*;

pub fn format_opdata_list(name: &str, data: &[Opdata]) -> String {
    let mut forms = Vec::new();
    for data in data {
        forms.extend(format_opdata(name, data));
    }
    forms.join("\n")
}

pub fn format_opdata(name: &str, data: &Opdata) -> Vec<String> {
    let opsizes = if data.flags.contains(AUTO_SIZE) {&b"qwd"[..]}
             else if data.flags.contains(AUTO_NO32) {&b"qw"[..]}
             else if data.flags.contains(AUTO_REXW) {&b"qd"[..]}
             else if data.flags.contains(AUTO_VEXL) {&b"ho"[..]}
             else                                   {&b"!"[..]};

    let mut forms = Vec::new();
    for opsize in opsizes.iter().cloned() {
        let mut buf = String::new();
        buf.push_str(">>> ");
        buf.push_str(name);
        let mut first = true;
        for (ty, size) in FormatStringIterator::new(data.args) {
            if first {
                buf.push_str(" ");
                first = false;
            } else {
                buf.push_str(", ");
            }
            buf.push_str(&format_arg(ty, size, opsize))
        }
        forms.push(buf);
    }
    forms
}

static REGS: [&'static str; 16] = ["a",  "d",  "c",   "b",   "bp",  "sp",  "si",  "di",
                                   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"];
static SEGREGS: [&'static str; 6] = ["es", "cs", "ss", "ds", "fs", "gs"];

fn format_arg(ty: u8, mut size: u8, opsize: u8) -> Cow<'static, str> {
    if size == b'*' {
        size = if opsize == b'q' && (ty == b'i' || ty == b'o') {
            b'd'
        } else {
            opsize
        };
    }

    fn format_size(size: u8) -> &'static str {
        match size {
            b'b' => "8",
            b'w' => "16",
            b'd' => "32",
            b'q' => "64",
            b'p' => "80",
            b'o' => "128",
            b'h' => "256",
            _ => ""
        }
    }

    match ty {
        b'i' => format!("imm{}",      format_size(size)).into(),
        b'o' => format!("rel{}off",   format_size(size)).into(),
        b'm' => format!("mem{}",      format_size(size)).into(),
        b'k' => format!("vm32addr{}", format_size(size)).into(),
        b'l' => format!("vm64addr{}", format_size(size)).into(),
        b'r' => format!("reg{}",      format_size(size)).into(),
        b'f' => "st".into(),
        b'x' => "mmx".into(),
        b'y' => (if size == b'h' {"ymm"} else {"xmm"}).into(),
        b's' => "segreg".into(),
        b'c' => "creg".into(),
        b'd' => "dreg".into(),
        b'v' => format!("reg/mem{}", format_size(size)).into(),
        b'u' => format!("mmx/mem{}", format_size(size)).into(),
        b'w' => format!("{}mm/mem{}", if size == b'h' {"y"} else {"x"}, format_size(size)).into(),
        b'A'...b'P' => {
            let i = ty as usize - 'A' as usize;
            match size {
                b'b' => if i < 4 { format!("{}l", REGS[i]).into() }
                   else if i < 8 { REGS[i].into() }
                   else          { format!("{}b", REGS[i]).into() },
                b'w' => if i < 4 { format!("{}x", REGS[i]).into() }
                   else if i < 8 { REGS[i].into() }
                   else          { format!("{}w", REGS[i]).into() },
                b'd' => if i < 4 { format!("e{}x",REGS[i]).into() }
                   else if i < 8 { format!("e{}", REGS[i]).into() }
                   else          { format!("{}d", REGS[i]).into() },
                b'q' => if i < 4 { format!("r{}x",REGS[i]).into() }
                   else if i < 8 { format!("r{}", REGS[i]).into() }
                   else          { format!("r{}", REGS[i]).into() },
                _ => panic!("invalid formatting data")
            }
        },
        b'Q'...b'V' => SEGREGS[ty as usize - 'Q' as usize].into(),
        b'W' => "cr8".into(),
        b'X' => "st0".into(),
        _ => panic!("invalid formatting data")
    }
}