<commit_before>static MD2_S_Table: &'static [u8] = &[
    0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
    0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
    0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
    0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
    0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
    0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
    0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
    0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
    0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
    0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
    0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
    0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
    0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
    0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
    0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
    0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
];

/// Struct storing the necessary state for the Message Digest 2 (MD2) hash function
/// Code is ported and `rustified` from libtomcrypt
#[allow(non_camel_case_types)]
pub struct MD2 {
    check_sum : [u8, ..16],
    x         : [u8, ..48],
    buffer    : [u8, ..16],
    cur_len   : uint
}

fn md2_compress(state: &mut MD2) {
   /* copy block to state.x */
   for i in range(0, 16) {
       state.x[16 + i] = state.buffer[i];
       state.x[32 + i] = state.x[i] ^ state.x[16 + i];
   }

   let mut t = 0u8;
   /* perform 18 rounds */
   for round in range(0, 18) {
       for i in range(0, 48) {
           state.x[i] ^= MD2_S_Table[(t & 255) as uint];
           t = state.x[i];
       }
       t = t + round & 255;
   }
}

#[allow(non_snake_case)]
fn md2_update_checksum(state: &mut MD2) {
    let mut L = state.check_sum[15];
    for i in range(0, 16) {
        /* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the reference
         * source code [and test vectors] say otherwise. */
        state.check_sum[i] ^= MD2_S_Table[(state.buffer[i] ^ L) as uint] & 255;
        L = state.check_sum[i];
    }
}

impl MD2 {
    /// Creates a new MD2 instance
    ///
    /// # Returns
    /// * The created instance
    pub fn new() -> MD2 {
        MD2 {
            check_sum : [0, ..16],
            x         : [0, ..48],
            buffer    : [0, ..16],
            cur_len   : 0
        }
    }

    fn reset(&mut self) {
        self.check_sum = [0, ..16];
        self.x         = [0, ..48];
        self.buffer    = [0, ..16];
        self.cur_len   = 0;
    }
}

impl ::hashes::HashFunction for MD2 {
    fn set_input(&mut self, input: &[u8]) {
        use std::cmp::{min};

        // First reset the hash state
        self.reset();

        let mut index = 0u;
        let mut in_len = input.len();

        loop {
            if in_len <= 0 {
                break;
            }

            let n = min(in_len, (16 - self.cur_len));
            for i in range(0, n) {
                self.buffer[self.cur_len + i] = input[index + i];
            }
            self.cur_len += n;
            index         += n;
            in_len       -= n;

            /* if 16 bytes are filled compress and update checksum */
            if self.cur_len == 16 {
                md2_compress(self);
                md2_update_checksum(self);
                self.cur_len = 0;
            }
        }
    }

    fn hash(&mut self) {
        // When is this the case?
        if self.cur_len >= self.buffer.len() {
           fail!()
        }

        /* pad the message */
        let k: u8 = 16u8 - self.cur_len as u8;
        for i in range(self.cur_len, 16) {
            self.buffer[i] = k;
        }

        /* hash and update */
        md2_compress(self);
        md2_update_checksum(self);

        /* hash checksum */
        for i in range(0, 16) {
            self.buffer[i] = self.check_sum[i];
        }
        md2_compress(self);
    }

    fn get_output(&mut self, output: &mut [u8]) {
        assert!(output.len() >= self.get_output_length())

        for i in range(0, 16) {
            output[i] = self.x[i];
        }
    }

    fn get_blocksize(&self) -> uint { 16 }

    fn get_output_length_in_bits(&self) -> uint { 128 }
}

#[cfg(test)]
mod tests {
    use hashes::md2::MD2;
    use hashes::test::{HashTestCase, perform_hash_test};

    #[test]
    fn test_md2() {
        let tests = vec![
            hash_test!(
                "",
                vec![0x83,0x50,0xe5,0xa3,0xe2,0x4c,0x15,0x3d,0xf2,0x27,0x5c,0x9f,0x80,0x69,0x27,0x73],
                "8350e5a3e24c153df2275c9f80692773"),
            hash_test!(
                "a",
                vec![0x32,0xec,0x01,0xec,0x4a,0x6d,0xac,0x72,0xc0,0xab,0x96,0xfb,0x34,0xc0,0xb5,0xd1],
                "32ec01ec4a6dac72c0ab96fb34c0b5d1"),
            hash_test!(
                "message digest",
                vec![0xab,0x4f,0x49,0x6b,0xfb,0x2a,0x53,0x0b,0x21,0x9f,0xf3,0x30,0x31,0xfe,0x06,0xb0],
                "ab4f496bfb2a530b219ff33031fe06b0"),
            hash_test!(
                "abcdefghijklmnopqrstuvwxyz",
                vec![0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b],
                "4e8ddff3650292ab5a4108c3aa47940b"),
            hash_test!(
                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
                vec![0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd],
                "da33def2a42df13975352846c30338cd"),
            hash_test!(
                "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
                vec![0xd5,0x97,0x6f,0x79,0xd8,0x3d,0x3a,0x0d,0xc9,0x80,0x6c,0x3c,0x66,0xf3,0xef,0xd8],
                "d5976f79d83d3a0dc9806c3c66f3efd8")
        ];

        let mut md2 = MD2::new();
        for t in tests.iter() {
            perform_hash_test(&mut md2, t);
        }
    }
}
<commit_msg>Update to rust master<commit_after>static MD2_S_TABLE: &'static [u8] = &[
    0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
    0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
    0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
    0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
    0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
    0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
    0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
    0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
    0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
    0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
    0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
    0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
    0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
    0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
    0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
    0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
];

/// Struct storing the necessary state for the Message Digest 2 (MD2) hash function
/// Code is ported and `rustified` from libtomcrypt
#[allow(non_camel_case_types)]
pub struct MD2 {
    check_sum : [u8, ..16],
    x         : [u8, ..48],
    buffer    : [u8, ..16],
    cur_len   : uint
}

fn md2_compress(state: &mut MD2) {
   /* copy block to state.x */
   for i in range(0, 16) {
       state.x[16 + i] = state.buffer[i];
       state.x[32 + i] = state.x[i] ^ state.x[16 + i];
   }

   let mut t = 0u8;
   /* perform 18 rounds */
   for round in range(0, 18) {
       for i in range(0, 48) {
           state.x[i] ^= MD2_S_TABLE[(t & 255) as uint];
           t = state.x[i];
       }
       t = t + round & 255;
   }
}

#[allow(non_snake_case)]
fn md2_update_checksum(state: &mut MD2) {
    let mut L = state.check_sum[15];
    for i in range(0, 16) {
        /* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the reference
         * source code [and test vectors] say otherwise. */
        state.check_sum[i] ^= MD2_S_TABLE[(state.buffer[i] ^ L) as uint] & 255;
        L = state.check_sum[i];
    }
}

impl MD2 {
    /// Creates a new MD2 instance
    ///
    /// # Returns
    /// * The created instance
    pub fn new() -> MD2 {
        MD2 {
            check_sum : [0, ..16],
            x         : [0, ..48],
            buffer    : [0, ..16],
            cur_len   : 0
        }
    }

    fn reset(&mut self) {
        self.check_sum = [0, ..16];
        self.x         = [0, ..48];
        self.buffer    = [0, ..16];
        self.cur_len   = 0;
    }
}

impl ::hashes::HashFunction for MD2 {
    fn set_input(&mut self, input: &[u8]) {
        use std::cmp::{min};

        // First reset the hash state
        self.reset();

        let mut index = 0u;
        let mut in_len = input.len();

        loop {
            if in_len <= 0 {
                break;
            }

            let n = min(in_len, (16 - self.cur_len));
            for i in range(0, n) {
                self.buffer[self.cur_len + i] = input[index + i];
            }
            self.cur_len += n;
            index         += n;
            in_len       -= n;

            /* if 16 bytes are filled compress and update checksum */
            if self.cur_len == 16 {
                md2_compress(self);
                md2_update_checksum(self);
                self.cur_len = 0;
            }
        }
    }

    fn hash(&mut self) {
        // When is this the case?
        if self.cur_len >= self.buffer.len() {
           panic!("self.cur_len >= self.buffer.len()")
        }

        /* pad the message */
        let k: u8 = 16u8 - self.cur_len as u8;
        for i in range(self.cur_len, 16) {
            self.buffer[i] = k;
        }

        /* hash and update */
        md2_compress(self);
        md2_update_checksum(self);

        /* hash checksum */
        for i in range(0, 16) {
            self.buffer[i] = self.check_sum[i];
        }
        md2_compress(self);
    }

    fn get_output(&mut self, output: &mut [u8]) {
        assert!(output.len() >= self.get_output_length())

        for i in range(0, 16) {
            output[i] = self.x[i];
        }
    }

    fn get_blocksize(&self) -> uint { 16 }

    fn get_output_length_in_bits(&self) -> uint { 128 }
}

#[cfg(test)]
mod tests {
    use hashes::md2::MD2;
    use hashes::test::{HashTestCase, perform_hash_test};

    #[test]
    fn test_md2() {
        let tests = vec![
            hash_test!(
                "",
                vec![0x83,0x50,0xe5,0xa3,0xe2,0x4c,0x15,0x3d,0xf2,0x27,0x5c,0x9f,0x80,0x69,0x27,0x73],
                "8350e5a3e24c153df2275c9f80692773"),
            hash_test!(
                "a",
                vec![0x32,0xec,0x01,0xec,0x4a,0x6d,0xac,0x72,0xc0,0xab,0x96,0xfb,0x34,0xc0,0xb5,0xd1],
                "32ec01ec4a6dac72c0ab96fb34c0b5d1"),
            hash_test!(
                "message digest",
                vec![0xab,0x4f,0x49,0x6b,0xfb,0x2a,0x53,0x0b,0x21,0x9f,0xf3,0x30,0x31,0xfe,0x06,0xb0],
                "ab4f496bfb2a530b219ff33031fe06b0"),
            hash_test!(
                "abcdefghijklmnopqrstuvwxyz",
                vec![0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b],
                "4e8ddff3650292ab5a4108c3aa47940b"),
            hash_test!(
                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
                vec![0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd],
                "da33def2a42df13975352846c30338cd"),
            hash_test!(
                "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
                vec![0xd5,0x97,0x6f,0x79,0xd8,0x3d,0x3a,0x0d,0xc9,0x80,0x6c,0x3c,0x66,0xf3,0xef,0xd8],
                "d5976f79d83d3a0dc9806c3c66f3efd8")
        ];

        let mut md2 = MD2::new();
        for t in tests.iter() {
            perform_hash_test(&mut md2, t);
        }
    }
}
<|endoftext|>


<commit_before>use dispatch_table::{DispatchTable, DispatchFn};
use spin::RwLock;
use isr;

#[derive(Copy, Clone, Default)]
#[repr(packed)]
struct IDTEntry {
    base_low: u16,
    selector: u16,
    always0: u8,
    flags: u8,
    base_high: u16,
    base_highest: u32,
    _reserved: u32,
}

pub struct IDT([IDTEntry; 20]);

lazy_static! {
    static ref INTERRUPT_TABLE: RwLock<DispatchTable<u64, InterruptCPUState>> =
        RwLock::new(DispatchTable::new(25));
    static ref DESCRIPTOR_TABLE: RwLock<IDT> = RwLock::new(IDT([Default::default(); 20]));
}

impl IDT {
    fn set_entry(&mut self, num: usize, base: u64, selector: u16, flags: u8) {
        self.0[num].base_low = (base & 0xffff) as u16;
        self.0[num].base_high = ((base >> 16) & 0xffff) as u16;
        self.0[num].base_highest = (base >> 32) as u32;
        self.0[num].always0 = 0;
        self.0[num].selector = selector;
        self.0[num].flags = flags;
    }
}

#[repr(C)]
pub struct InterruptCPUState {
    ds: u64,
    r15: u64,
    r14: u64,
    r13: u64,
    r12: u64,
    r11: u64,
    r10: u64,
    r9: u64,
    r8: u64,
    rdi: u64,
    rsi: u64,
    rbp: u64,
    rdx: u64,
    rcx: u64,
    rbx: u64,
    rax: u64,
    interrupt_number: u64,
    error_code: u64,
    rip: u64,
    cs: u64,
    rflags: u64,
    rsp: u64,
    ss: u64,
}

pub fn register_interrupt_handler(interrupt: u64,
                                  stub: isr::InterruptServiceRoutine,
                                  handler: DispatchFn<u64, InterruptCPUState>) {
    INTERRUPT_TABLE.write().register(interrupt, handler);
    DESCRIPTOR_TABLE.write().set_entry(interrupt as usize, stub as u64, 0x08, 0x8e);
}

pub fn unregister_interrupt_handler(interrupt: u64) {
    INTERRUPT_TABLE.write().unregister(interrupt);
}

#[no_mangle]
pub extern "C" fn dispatch_interrupt(state: &mut InterruptCPUState) {
    INTERRUPT_TABLE.read().dispatch(state.interrupt_number, state);
}

fn default_handler(_interrupt_number: u64, _regs: &mut InterruptCPUState) -> bool {
    true
}

pub fn init_interrupt_handlers() {
    for i in 0..20 {
        register_interrupt_handler(i, isr::ISR[i as usize], default_handler);
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {

    use interrupts;
    use vmx;
    use cli;
    use core::mem;

    fn new_host_idt_descriptor() -> vmx::CPUTableDescriptor {
        let base = (*interrupts::DESCRIPTOR_TABLE.write()).0.as_ptr() as u64;
        vmx::CPUTableDescriptor {
            base: base,
            limit: (mem::size_of::<interrupts::IDT>() - 1) as u16,
        }
    }

    pub fn run() {
        test_load_and_restore_idt();
    }

    fn test_load_and_restore_idt() {
        cli::ClearLocalInterruptsGuard::new();
        let idt_desc = new_host_idt_descriptor();
        let mut orig_idt_desc: vmx::CPUTableDescriptor = Default::default();
        vmx::sidt(&mut orig_idt_desc);
        vmx::lidt(&idt_desc);
        vmx::lidt(&orig_idt_desc);
    }
}
<commit_msg>Refactor IDT<commit_after>use dispatch_table::{DispatchTable, DispatchFn};
use spin::RwLock;
use core::mem;
use cli;
use isr;

#[derive(Copy, Clone, Default)]
#[repr(packed)]
struct IDTEntry {
    base_low: u16,
    selector: u16,
    always0: u8,
    flags: u8,
    base_high: u16,
    base_highest: u32,
    _reserved: u32,
}

#[derive(Default)]
pub struct IDT([IDTEntry; 20]);

#[repr(C)]
pub struct InterruptCPUState {
    ds: u64,
    r15: u64,
    r14: u64,
    r13: u64,
    r12: u64,
    r11: u64,
    r10: u64,
    r9: u64,
    r8: u64,
    rdi: u64,
    rsi: u64,
    rbp: u64,
    rdx: u64,
    rcx: u64,
    rbx: u64,
    rax: u64,
    interrupt_number: u64,
    error_code: u64,
    rip: u64,
    cs: u64,
    rflags: u64,
    rsp: u64,
    ss: u64,
}

pub fn lidt(idt_desc: *const IDTDescriptor) {
    unsafe {
        asm!(
            "lidt ($0)"
            :
            : "r"(idt_desc)
            :
            );
    }
}

pub fn sidt(idt_desc: *mut IDTDescriptor) {
    unsafe {
        asm!(
            "sidt ($0)"
            :
            : "r"(idt_desc)
            :
            );
    }
}

impl IDT {
    fn set_entry(&mut self, num: usize, base: u64, selector: u16, flags: u8) {
        self.0[num].base_low = (base & 0xffff) as u16;
        self.0[num].base_high = ((base >> 16) & 0xffff) as u16;
        self.0[num].base_highest = (base >> 32) as u32;
        self.0[num].always0 = 0;
        self.0[num].selector = selector;
        self.0[num].flags = flags;
    }
}

pub struct InterruptTable {
    descriptor_table: cli::ClearLocalInterruptsGuard<IDT>,
    dispatch_table: DispatchTable<u64, InterruptCPUState>,
}

impl Default for InterruptTable {
    fn default() -> Self {
        InterruptTable {
            descriptor_table: Default::default(),
            dispatch_table: DispatchTable::new(20),
        }
    }
}

impl InterruptTable {
    fn as_ptr(&self) -> *const IDT {
        (*self.descriptor_table).0.as_ptr() as *const IDT
    }
}

lazy_static! {
    static ref INTERRUPT_TABLE: RwLock<InterruptTable> = Default::default();
}

pub fn register_interrupt_handler(interrupt: u64,
                                  stub: isr::InterruptServiceRoutine,
                                  handler: DispatchFn<u64, InterruptCPUState>) {
    let mut table = INTERRUPT_TABLE.write();
    table.dispatch_table.register(interrupt, handler);
    table.descriptor_table.set_entry(interrupt as usize, stub as u64, 0x08, 0x8e);
}

pub fn unregister_interrupt_handler(interrupt: u64) {
    let mut table = INTERRUPT_TABLE.write();
    table.dispatch_table.unregister(interrupt);
    table.descriptor_table.set_entry(interrupt as usize, 0, 0, 0);
}

#[no_mangle]
pub extern "C" fn dispatch_interrupt(state: &mut InterruptCPUState) {
    INTERRUPT_TABLE.read().dispatch_table.dispatch(state.interrupt_number, state);
}

fn default_handler(_interrupt_number: u64, _regs: &mut InterruptCPUState) -> bool {
    true
}

pub fn init_interrupt_handlers() {
    for i in 0..20 {
        register_interrupt_handler(i, isr::ISR[i as usize], default_handler);
    }
}

#[derive(Default)]
#[repr(packed)]
pub struct IDTDescriptor {
    pub limit: u16,
    pub base: u64,
}

impl IDTDescriptor {
    pub fn new() -> cli::ClearLocalInterruptsGuard<IDTDescriptor> {
        cli::ClearLocalInterruptsGuard::new(IDTDescriptor {
            limit: (mem::size_of::<IDT>() - 1) as u16,
            base: (*INTERRUPT_TABLE).read().as_ptr() as u64,
        })
    }

    pub fn from_cpu() -> cli::ClearLocalInterruptsGuard<IDTDescriptor> {
        let mut current_idt_ptr: IDTDescriptor = Default::default();
        sidt(&mut current_idt_ptr);
        cli::ClearLocalInterruptsGuard::new(current_idt_ptr)
    }

    pub fn load(&self) {
        lidt(self);
    }
}

#[cfg(feature = "runtime_tests")]
pub mod runtime_tests {

    use interrupts::IDTDescriptor;

    pub fn run() {
        test_load_and_restore_idt();
    }

    fn test_load_and_restore_idt() {
        let orig_idt_desc = IDTDescriptor::from_cpu();
        let idt_desc = IDTDescriptor::new();
        idt_desc.load();
        orig_idt_desc.load();
    }
}
<|endoftext|>


<commit_before>pub mod files;

use std::cmp;
use std::io::Write;

const MAX_PATCH_LEN: usize = 0xFFFF;

#[derive(Debug)]
pub struct Ips {
    buffer: Vec<u8>
}

impl Ips {
    pub fn new(buffer: &Vec<u8>) -> Self {
        Ips {
            buffer: buffer.clone()
        }
    }

    pub fn diff(&self, change: &Vec<u8>) -> Vec<Patch> {
        let (change_within, additional) = change.split_at(self.buffer.len());
        let mut pairs = (0..).zip(self.buffer.iter().zip(change_within));

        let mut patches: Vec<Patch> = vec![];
        let mut index = 0;
        let mut data = vec![];

        while let Some((offset, (&before, &after))) = pairs.next() {
            if before != after {
                if data.is_empty() {
                    index = offset;
                }
                data.push(after);
            } else if ! data.is_empty() {
                let patch = Patch::new(index, data);
                patches.push(patch);
                data = vec![];
            }
        };

        for chunk in additional.chunks(MAX_PATCH_LEN) {
            let patch = Patch::new(self.buffer.len() as u32, chunk.to_vec());
            patches.push(patch);
        }

        patches
    }

    pub fn patch(&self, change: &Vec<Patch>) -> Vec<u8> {
        let total_size = cmp::max(self.buffer.len(), patch_max_len(&change).unwrap());
        println!("{:?}", total_size);

        let mut output = Vec::with_capacity(total_size);
        let _ = output.write(&self.buffer);

        println!("before: {:?}", output);
        for patch in change {
            {
                let (_, mut skipped) = output.split_at_mut(patch.addr as usize);
                skipped.write(&patch.data)
            }.map(|written_len| {
                let (_, unwritten_data) = patch.data.split_at(written_len);
                for &b in unwritten_data {
                    output.push(b);
                }
            });
        }
        println!("after: {:?}", output);
        output
    }

}

pub fn patch_max_len(patch: &[Patch]) -> Option<usize> {
    patch.iter().map(|x| x.addr as usize + x.data.len()).max()
}

pub fn serialize_patches(patches: Vec<Patch>) -> Vec<u8> {
    let patch_contents: Vec<u8> = patches.iter().flat_map(|p| p.bytes()).collect();
    let mut binary: Vec<u8> = "PATCH".bytes().collect();
    binary.extend(patch_contents);
    binary.extend("EOF".bytes().collect::<Vec<_>>());
    binary
}

pub fn unserialize_patches(binary: Vec<u8>) -> Option<Vec<Patch>> {
    let mut patches: Vec<Patch> = Vec::new();

    let slice = &binary;
    let (header, mut slice) = slice.split_at(5);

    if header != b"PATCH" {
        return None;
    }

    loop {
        // TODO support RLE'd patches
        let (addr_slice, rest) = slice.split_at(3);
        let (len_slice, rest) = rest.split_at(2);

        if (! addr_slice.is_empty()) && len_slice.len() < 2 {
            // Malformed data
            return None;
        }

        let mut addr_array = [0; 3];
        addr_array.clone_from_slice(addr_slice);
        let addr = Patch::unserialize_addr_array(addr_array);

        let mut len_array = [0; 2];
        len_array.clone_from_slice(len_slice);
        let len = Patch::unserialize_len(len_array);

        let (data, rest) = rest.split_at(len);

        if data.len() < len {
            // Malformed data
            return None;
        }

        let patch = Patch {
            addr: addr,
            data: data.to_vec()
        };

        patches.push(patch);

        slice = rest;

        let possible_eof: Vec<u8> = rest.iter().take(3).cloned().collect();
        if &possible_eof == b"EOF" {
            // We are done here
            break;
        }
    }

    Some(patches)
}

#[derive(Debug, PartialEq)]
pub struct Patch {
    addr: u32,
    data: Vec<u8>
}

impl Patch {
    pub fn new(addr: u32, data: Vec<u8>) -> Self {
        assert!(addr <= 0xFFFFFF);
        Patch {
            addr: addr,
            data: data
        }
    }

    pub fn bytes(&self) -> Vec<u8> {
        let mut bytes: Vec<u8> = self.serialize_addr();
        let len = self.serialize_len();
        bytes.extend(len);
        bytes.extend(&self.data);
        bytes
    }

    pub fn unserialize_addr_array(addr: [u8; 3]) -> u32 {
        ((addr[0] as u32) << 16) | ((addr[1] as u32) << 8) | addr[2] as u32
    }

    pub fn serialize_addr(&self) -> Vec<u8> {
        vec![(self.addr >> 16) as u8, (self.addr >> 8) as u8, self.addr as u8]
    }

    pub fn unserialize_len(addr: [u8; 2]) -> usize {
        (((addr[0] as u32) << 8) | addr[1] as u32) as usize
    }

    pub fn serialize_len(&self) -> Vec<u8> {
        vec![(self.data.len() >> 8) as u8, self.data.len() as u8]
    }
}
<commit_msg>Don't silence useful warnings<commit_after>pub mod files;

use std::cmp;
use std::io::Write;

const MAX_PATCH_LEN: usize = 0xFFFF;

#[derive(Debug)]
pub struct Ips {
    buffer: Vec<u8>
}

impl Ips {
    pub fn new(buffer: &Vec<u8>) -> Self {
        Ips {
            buffer: buffer.clone()
        }
    }

    pub fn diff(&self, change: &Vec<u8>) -> Vec<Patch> {
        let (change_within, additional) = change.split_at(self.buffer.len());
        let mut pairs = (0..).zip(self.buffer.iter().zip(change_within));

        let mut patches: Vec<Patch> = vec![];
        let mut index = 0;
        let mut data = vec![];

        while let Some((offset, (&before, &after))) = pairs.next() {
            if before != after {
                if data.is_empty() {
                    index = offset;
                }
                data.push(after);
            } else if ! data.is_empty() {
                let patch = Patch::new(index, data);
                patches.push(patch);
                data = vec![];
            }
        };

        for chunk in additional.chunks(MAX_PATCH_LEN) {
            let patch = Patch::new(self.buffer.len() as u32, chunk.to_vec());
            patches.push(patch);
        }

        patches
    }

    pub fn patch(&self, change: &Vec<Patch>) -> Vec<u8> {
        let total_size = cmp::max(self.buffer.len(), patch_max_len(&change).unwrap());
        println!("{:?}", total_size);

        let mut output = Vec::with_capacity(total_size);
        output.write(&self.buffer);

        println!("before: {:?}", output);
        for patch in change {
            {
                let (_, mut skipped) = output.split_at_mut(patch.addr as usize);
                skipped.write(&patch.data)
            }.map(|written_len| {
                let (_, unwritten_data) = patch.data.split_at(written_len);
                for &b in unwritten_data {
                    output.push(b);
                }
            });
        }
        println!("after: {:?}", output);
        output
    }

}

pub fn patch_max_len(patch: &[Patch]) -> Option<usize> {
    patch.iter().map(|x| x.addr as usize + x.data.len()).max()
}

pub fn serialize_patches(patches: Vec<Patch>) -> Vec<u8> {
    let patch_contents: Vec<u8> = patches.iter().flat_map(|p| p.bytes()).collect();
    let mut binary: Vec<u8> = "PATCH".bytes().collect();
    binary.extend(patch_contents);
    binary.extend("EOF".bytes().collect::<Vec<_>>());
    binary
}

pub fn unserialize_patches(binary: Vec<u8>) -> Option<Vec<Patch>> {
    let mut patches: Vec<Patch> = Vec::new();

    let slice = &binary;
    let (header, mut slice) = slice.split_at(5);

    if header != b"PATCH" {
        return None;
    }

    loop {
        // TODO support RLE'd patches
        let (addr_slice, rest) = slice.split_at(3);
        let (len_slice, rest) = rest.split_at(2);

        if (! addr_slice.is_empty()) && len_slice.len() < 2 {
            // Malformed data
            return None;
        }

        let mut addr_array = [0; 3];
        addr_array.clone_from_slice(addr_slice);
        let addr = Patch::unserialize_addr_array(addr_array);

        let mut len_array = [0; 2];
        len_array.clone_from_slice(len_slice);
        let len = Patch::unserialize_len(len_array);

        let (data, rest) = rest.split_at(len);

        if data.len() < len {
            // Malformed data
            return None;
        }

        let patch = Patch {
            addr: addr,
            data: data.to_vec()
        };

        patches.push(patch);

        slice = rest;

        let possible_eof: Vec<u8> = rest.iter().take(3).cloned().collect();
        if &possible_eof == b"EOF" {
            // We are done here
            break;
        }
    }

    Some(patches)
}

#[derive(Debug, PartialEq)]
pub struct Patch {
    addr: u32,
    data: Vec<u8>
}

impl Patch {
    pub fn new(addr: u32, data: Vec<u8>) -> Self {
        assert!(addr <= 0xFFFFFF);
        Patch {
            addr: addr,
            data: data
        }
    }

    pub fn bytes(&self) -> Vec<u8> {
        let mut bytes: Vec<u8> = self.serialize_addr();
        let len = self.serialize_len();
        bytes.extend(len);
        bytes.extend(&self.data);
        bytes
    }

    pub fn unserialize_addr_array(addr: [u8; 3]) -> u32 {
        ((addr[0] as u32) << 16) | ((addr[1] as u32) << 8) | addr[2] as u32
    }

    pub fn serialize_addr(&self) -> Vec<u8> {
        vec![(self.addr >> 16) as u8, (self.addr >> 8) as u8, self.addr as u8]
    }

    pub fn unserialize_len(addr: [u8; 2]) -> usize {
        (((addr[0] as u32) << 8) | addr[1] as u32) as usize
    }

    pub fn serialize_len(&self) -> Vec<u8> {
        vec![(self.data.len() >> 8) as u8, self.data.len() as u8]
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

#[macro_use] extern crate frunk;
extern crate test;

use frunk::hlist::*;
use test::Bencher;

#[bench]
fn creating_hlist(b: &mut Bencher) {
    b.iter(|| hlist![1, 2, 3.3f32, "hi2", true])
}

#[bench]
fn creating_tuple2(b: &mut Bencher) {
    b.iter(|| (1, (2, (3.3f32, ("hi2", true)))))
}

#[bench]
fn hlist_into_tuple2(b: &mut Bencher) {
    let h = hlist![1, 2, 3.3f32, "hi2", true];
    b.iter(|| h.into_tuple2())
}

#[bench]
fn hlist_append(b: &mut Bencher) {
    let h1 = hlist![1, 2, 3.3f32, "hi2", true];
    let h2 = hlist![true, "blue", "varcity"];
    b.iter(|| h1 + h2 )
}<commit_msg>Add benchmark for hlist_pat match<commit_after>#![feature(test)]

#[macro_use] extern crate frunk;
extern crate test;

use frunk::hlist::*;
use test::Bencher;

#[bench]
fn creating_hlist(b: &mut Bencher) {
    b.iter(|| hlist![1, 2, 3.3f32, "hi2", true])
}

#[bench]
fn creating_tuple2(b: &mut Bencher) {
    b.iter(|| (1, (2, (3.3f32, ("hi2", true)))))
}

#[bench]
fn hlist_into_tuple2(b: &mut Bencher) {
    let h = hlist![1, 2, 3.3f32, "hi2", true];
    b.iter(|| h.into_tuple2())
}

#[bench]
fn hlist_into_tuple2_match(b: &mut Bencher) {
    let h = hlist![1, 2, 3.3f32, "hi2", true];
    b.iter(|| {
        let (a, (b, (c, (d, e)))) = h.into_tuple2();
        (a, b, c, d, e)
    })
}

#[bench]
fn hlist_into_hlist_pat_match(b: &mut Bencher) {
    let h = hlist![1, 2, 3.3f32, "hi2", true];
    b.iter(|| {
        let hlist_pat!(a, b, c, d, e) = h;
        (a, b, c, d, e)
    })
}

#[bench]
fn hlist_append(b: &mut Bencher) {
    let h1 = hlist![1, 2, 3.3f32, "hi2", true];
    let h2 = hlist![true, "blue", "varcity"];
    b.iter(|| h1 + h2 )
}<|endoftext|>


<commit_before>use libc::{c_char, c_void};

#[link(name="dl")]
extern {
        fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void;
}

const RTLD_NEXT: *const c_void = -1isize as *const c_void;

pub unsafe fn dlsym_next(symbol: &'static str) -> *const u8 {
    let ptr = dlsym(RTLD_NEXT, symbol.as_ptr() as *const c_char);
    if ptr.is_null() {
        panic!("redhook: Unable to find underlying function for {}", symbol);
    }
    ptr as *const u8
}

/* Rust doesn't directly expose __attribute__((constructor)), but this
 * is how GNU implements it. */
#[link_section=".init_array"]
pub static INITIALIZE_CTOR: extern fn() = ::initialize;

#[macro_export]
macro_rules! hook {
    (fn $real_fn:ident ( $($v:ident : $t:ty),* ) -> $r:ty => $hook_fn:ident $body:block) => {
        #[allow(non_camel_case_types)]
        pub struct $real_fn {__private_field: ()}
        #[allow(non_upper_case_globals)]
        static $real_fn: $real_fn = $real_fn {__private_field: ()};

        impl $real_fn {
            fn get(&self) -> unsafe extern fn ( $($v : $t),* ) -> $r {
                use ::std::sync::{Once, ONCE_INIT};

                static mut REAL: *const u8 = 0 as *const u8;
                static mut ONCE: Once = ONCE_INIT;

                unsafe {
                    ONCE.call_once(|| {
                        REAL = $crate::ld_preload::dlsym_next(concat!(stringify!($real_fn), "\0"));
                    });
                    ::std::mem::transmute(REAL)
                }
            }

            #[no_mangle]
            pub unsafe fn $real_fn ( $($v : $t),* ) -> $r {
                if $crate::initialized() {
                    $hook_fn ( $($v),* )
                } else {
                    $real_fn.get() ( $($v),* )
                }
            }
        }

        pub fn $hook_fn ( $($v : $t),* ) -> $r {
            $body
        }
    };

    (fn $real_fn:ident ( $($v:ident : $t:ty),* ) => $hook_fn:ident $body:block) => {
        hook! { fn $real_fn ( $($v : $t),* ) -> () => $hook_fn $body }
    };
}

#[macro_export]
macro_rules! real {
    ($real_fn:ident) => {$real_fn.get()}
}
<commit_msg>ld_preload: Make replacement function use C ABI<commit_after>use libc::{c_char, c_void};

#[link(name="dl")]
extern {
        fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void;
}

const RTLD_NEXT: *const c_void = -1isize as *const c_void;

pub unsafe fn dlsym_next(symbol: &'static str) -> *const u8 {
    let ptr = dlsym(RTLD_NEXT, symbol.as_ptr() as *const c_char);
    if ptr.is_null() {
        panic!("redhook: Unable to find underlying function for {}", symbol);
    }
    ptr as *const u8
}

/* Rust doesn't directly expose __attribute__((constructor)), but this
 * is how GNU implements it. */
#[link_section=".init_array"]
pub static INITIALIZE_CTOR: extern fn() = ::initialize;

#[macro_export]
macro_rules! hook {
    (fn $real_fn:ident ( $($v:ident : $t:ty),* ) -> $r:ty => $hook_fn:ident $body:block) => {
        #[allow(non_camel_case_types)]
        pub struct $real_fn {__private_field: ()}
        #[allow(non_upper_case_globals)]
        static $real_fn: $real_fn = $real_fn {__private_field: ()};

        impl $real_fn {
            fn get(&self) -> unsafe extern fn ( $($v : $t),* ) -> $r {
                use ::std::sync::{Once, ONCE_INIT};

                static mut REAL: *const u8 = 0 as *const u8;
                static mut ONCE: Once = ONCE_INIT;

                unsafe {
                    ONCE.call_once(|| {
                        REAL = $crate::ld_preload::dlsym_next(concat!(stringify!($real_fn), "\0"));
                    });
                    ::std::mem::transmute(REAL)
                }
            }

            #[no_mangle]
            pub unsafe extern fn $real_fn ( $($v : $t),* ) -> $r {
                if $crate::initialized() {
                    $hook_fn ( $($v),* )
                } else {
                    $real_fn.get() ( $($v),* )
                }
            }
        }

        pub fn $hook_fn ( $($v : $t),* ) -> $r {
            $body
        }
    };

    (fn $real_fn:ident ( $($v:ident : $t:ty),* ) => $hook_fn:ident $body:block) => {
        hook! { fn $real_fn ( $($v : $t),* ) -> () => $hook_fn $body }
    };
}

#[macro_export]
macro_rules! real {
    ($real_fn:ident) => {$real_fn.get()}
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # The Rust Standard Library
//!
//! The Rust Standard Library provides the essential runtime
//! functionality for building portable Rust software.
//! It is linked to all Rust crates by default.
//!
//! ## Intrinsic types and operations
//!
//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html)
//! modules deal with unsafe pointers and memory manipulation.
//! [`kinds`](kinds/index.html) defines the special built-in traits,
//! and [`raw`](raw/index.html) the runtime representation of Rust types.
//! These are some of the lowest-level building blocks in Rust.
//!
//! ## Math on primitive types and math traits
//!
//! Although basic operations on primitive types are implemented
//! directly by the compiler, the standard library additionally
//! defines many common operations through traits defined in
//! mod [`num`](num/index.html).
//!
//! ## Pervasive types
//!
//! The [`option`](option/index.html) and [`result`](result/index.html)
//! modules define optional and error-handling types, `Option` and `Result`.
//! [`iter`](iter/index.html) defines Rust's iterator protocol
//! along with a wide variety of iterators.
//! [`Cell` and `RefCell`](cell/index.html) are for creating types that
//! manage their own mutability.
//!
//! ## Vectors, slices and strings
//!
//! The common container type, `Vec`, a growable vector backed by an
//! array, lives in the [`vec`](vec/index.html) module. References to
//! arrays, `&[T]`, more commonly called "slices", are built-in types
//! for which the [`slice`](slice/index.html) module defines many
//! methods.
//!
//! `&str`, a UTF-8 string, is a built-in type, and the standard library
//! defines methods for it on a variety of traits in the
//! [`str`](str/index.html) module. Rust strings are immutable;
//! use the `String` type defined in [`string`](string/index.html)
//! for a mutable string builder.
//!
//! For converting to strings use the [`format!`](fmt/index.html)
//! macro, and for converting from strings use the
//! [`FromStr`](from_str/index.html) trait.
//!
//! ## Platform abstractions
//!
//! Besides basic data types, the standard library is largely concerned
//! with abstracting over differences in common platforms, most notably
//! Windows and Unix derivatives. The [`os`](os/index.html) module
//! provides a number of basic functions for interacting with the
//! operating environment, including program arguments, environment
//! variables, and directory navigation. The [`path`](path/index.html)
//! module encapsulates the platform-specific rules for dealing
//! with file paths.
//!
//! `std` also includes modules for interoperating with the
//! C language: [`c_str`](c_str/index.html) and
//! [`c_vec`](c_vec/index.html).
//!
//! ## Concurrency, I/O, and the runtime
//!
//! The [`task`](task/index.html) module contains Rust's threading abstractions,
//! while [`comm`](comm/index.html) contains the channel types for message
//! passing. [`sync`](sync/index.html) contains further, primitive, shared
//! memory types, including [`atomics`](sync/atomics/index.html).
//!
//! Common types of I/O, including files, TCP, UDP, pipes, Unix domain sockets,
//! timers, and process spawning, are defined in the [`io`](io/index.html) module.
//!
//! Rust's I/O and concurrency depends on a small runtime interface
//! that lives, along with its support code, in mod [`rt`](rt/index.html).
//! While a notable part of the standard library's architecture, this
//! module is not intended for public use.
//!
//! ## The Rust prelude and macros
//!
//! Finally, the [`prelude`](prelude/index.html) defines a
//! common set of traits, types, and functions that are made available
//! to all code by default. [`macros`](macros/index.html) contains
//! all the standard macros, such as `assert!`, `fail!`, `println!`,
//! and `format!`, also available to all Rust code.

#![crate_name = "std"]
#![unstable]
#![comment = "The Rust standard library"]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/master/",
       html_playground_url = "http://play.rust-lang.org/")]

#![feature(macro_rules, globs, managed_boxes, linkage)]
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
#![feature(import_shadowing)]

// Don't link to std. We are std.
#![no_std]

#![allow(deprecated)]
#![deny(missing_doc)]

#![reexport_test_harness_main = "test_main"]

// When testing libstd, bring in libuv as the I/O backend so tests can print
// things and all of the std::io tests have an I/O interface to run on top
// of
#[cfg(test)] extern crate rustuv;
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate green;
#[cfg(test)] extern crate debug;
#[cfg(test)] #[phase(plugin, link)] extern crate log;

extern crate alloc;
extern crate unicode;
extern crate core;
extern crate "collections" as core_collections;
extern crate "rand" as core_rand;
extern crate "sync" as core_sync;
extern crate libc;
extern crate rustrt;

// Make std testable by not duplicating lang items. See #2912
#[cfg(test)] extern crate "std" as realstd;
#[cfg(test)] pub use realstd::kinds;
#[cfg(test)] pub use realstd::ops;
#[cfg(test)] pub use realstd::cmp;
#[cfg(test)] pub use realstd::ty;
#[cfg(test)] pub use realstd::boxed;
#[cfg(test)] pub use realstd::gc;

// NB: These reexports are in the order they should be listed in rustdoc

pub use core::any;
pub use core::bool;
pub use core::cell;
pub use core::clone;
#[cfg(not(test))] pub use core::cmp;
pub use core::default;
pub use core::finally;
pub use core::intrinsics;
pub use core::iter;
#[cfg(not(test))] pub use core::kinds;
pub use core::mem;
#[cfg(not(test))] pub use core::ops;
pub use core::ptr;
pub use core::raw;
pub use core::simd;
pub use core::tuple;
// FIXME #15320: primitive documentation needs top-level modules, this
// should be `std::tuple::unit`.
pub use core::unit;
#[cfg(not(test))] pub use core::ty;
pub use core::result;
pub use core::option;

pub use alloc::boxed;
#[deprecated = "use boxed instead"]
pub use boxed as owned;

pub use alloc::rc;

pub use core_collections::slice;
pub use core_collections::str;
pub use core_collections::string;
pub use core_collections::vec;

pub use rustrt::c_str;
pub use rustrt::local_data;

pub use unicode::char;

pub use core_sync::comm;

// Run tests with libgreen instead of libnative.
#[cfg(test)] #[start]
fn start(argc: int, argv: *const *const u8) -> int {
    green::start(argc, argv, rustuv::event_loop, test_main)
}

/* Exported macros */

pub mod macros;
pub mod bitflags;

mod rtdeps;

/* The Prelude. */

pub mod prelude;

/* Primitive types */

#[path = "num/float_macros.rs"] mod float_macros;
#[path = "num/int_macros.rs"]   mod int_macros;
#[path = "num/uint_macros.rs"]  mod uint_macros;

#[path = "num/int.rs"]  pub mod int;
#[path = "num/i8.rs"]   pub mod i8;
#[path = "num/i16.rs"]  pub mod i16;
#[path = "num/i32.rs"]  pub mod i32;
#[path = "num/i64.rs"]  pub mod i64;

#[path = "num/uint.rs"] pub mod uint;
#[path = "num/u8.rs"]   pub mod u8;
#[path = "num/u16.rs"]  pub mod u16;
#[path = "num/u32.rs"]  pub mod u32;
#[path = "num/u64.rs"]  pub mod u64;

#[path = "num/f32.rs"]   pub mod f32;
#[path = "num/f64.rs"]   pub mod f64;

pub mod rand;

pub mod ascii;

#[cfg(not(test))]
pub mod gc;

pub mod time;

/* Common traits */

pub mod from_str;
pub mod num;
pub mod to_string;

/* Common data structures */

pub mod collections;
pub mod hash;

/* Tasks and communication */

pub mod task;
pub mod sync;

/* Runtime and platform support */

pub mod c_vec;
pub mod dynamic_lib;
pub mod os;
pub mod io;
pub mod path;
pub mod fmt;

// FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable'
// but name resolution doesn't work without it being pub.
#[unstable]
pub mod rt;
mod failure;

// A curious inner-module that's not exported that contains the binding
// 'std' so that macro-expanded references to std::error and such
// can be resolved within libstd.
#[doc(hidden)]
mod std {
    // mods used for deriving
    pub use clone;
    pub use cmp;
    pub use hash;

    pub use comm; // used for select!()
    pub use fmt; // used for any formatting strings
    pub use io; // used for println!()
    pub use local_data; // used for local_data_key!()
    pub use option; // used for bitflags!{}
    pub use rt; // used for fail!()
    pub use vec; // used for vec![]

    // The test runner calls ::std::os::args() but really wants realstd
    #[cfg(test)] pub use realstd::os as os;
    // The test runner requires std::slice::Vector, so re-export std::slice just for it.
    #[cfg(test)] pub use slice;

    pub use collections; // vec!() uses MutableSeq
}
<commit_msg>Remove unstable marker from std::rt<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # The Rust Standard Library
//!
//! The Rust Standard Library provides the essential runtime
//! functionality for building portable Rust software.
//! It is linked to all Rust crates by default.
//!
//! ## Intrinsic types and operations
//!
//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html)
//! modules deal with unsafe pointers and memory manipulation.
//! [`kinds`](kinds/index.html) defines the special built-in traits,
//! and [`raw`](raw/index.html) the runtime representation of Rust types.
//! These are some of the lowest-level building blocks in Rust.
//!
//! ## Math on primitive types and math traits
//!
//! Although basic operations on primitive types are implemented
//! directly by the compiler, the standard library additionally
//! defines many common operations through traits defined in
//! mod [`num`](num/index.html).
//!
//! ## Pervasive types
//!
//! The [`option`](option/index.html) and [`result`](result/index.html)
//! modules define optional and error-handling types, `Option` and `Result`.
//! [`iter`](iter/index.html) defines Rust's iterator protocol
//! along with a wide variety of iterators.
//! [`Cell` and `RefCell`](cell/index.html) are for creating types that
//! manage their own mutability.
//!
//! ## Vectors, slices and strings
//!
//! The common container type, `Vec`, a growable vector backed by an
//! array, lives in the [`vec`](vec/index.html) module. References to
//! arrays, `&[T]`, more commonly called "slices", are built-in types
//! for which the [`slice`](slice/index.html) module defines many
//! methods.
//!
//! `&str`, a UTF-8 string, is a built-in type, and the standard library
//! defines methods for it on a variety of traits in the
//! [`str`](str/index.html) module. Rust strings are immutable;
//! use the `String` type defined in [`string`](string/index.html)
//! for a mutable string builder.
//!
//! For converting to strings use the [`format!`](fmt/index.html)
//! macro, and for converting from strings use the
//! [`FromStr`](from_str/index.html) trait.
//!
//! ## Platform abstractions
//!
//! Besides basic data types, the standard library is largely concerned
//! with abstracting over differences in common platforms, most notably
//! Windows and Unix derivatives. The [`os`](os/index.html) module
//! provides a number of basic functions for interacting with the
//! operating environment, including program arguments, environment
//! variables, and directory navigation. The [`path`](path/index.html)
//! module encapsulates the platform-specific rules for dealing
//! with file paths.
//!
//! `std` also includes modules for interoperating with the
//! C language: [`c_str`](c_str/index.html) and
//! [`c_vec`](c_vec/index.html).
//!
//! ## Concurrency, I/O, and the runtime
//!
//! The [`task`](task/index.html) module contains Rust's threading abstractions,
//! while [`comm`](comm/index.html) contains the channel types for message
//! passing. [`sync`](sync/index.html) contains further, primitive, shared
//! memory types, including [`atomics`](sync/atomics/index.html).
//!
//! Common types of I/O, including files, TCP, UDP, pipes, Unix domain sockets,
//! timers, and process spawning, are defined in the [`io`](io/index.html) module.
//!
//! Rust's I/O and concurrency depends on a small runtime interface
//! that lives, along with its support code, in mod [`rt`](rt/index.html).
//! While a notable part of the standard library's architecture, this
//! module is not intended for public use.
//!
//! ## The Rust prelude and macros
//!
//! Finally, the [`prelude`](prelude/index.html) defines a
//! common set of traits, types, and functions that are made available
//! to all code by default. [`macros`](macros/index.html) contains
//! all the standard macros, such as `assert!`, `fail!`, `println!`,
//! and `format!`, also available to all Rust code.

#![crate_name = "std"]
#![unstable]
#![comment = "The Rust standard library"]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/master/",
       html_playground_url = "http://play.rust-lang.org/")]

#![feature(macro_rules, globs, managed_boxes, linkage)]
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]
#![feature(import_shadowing)]

// Don't link to std. We are std.
#![no_std]

#![allow(deprecated)]
#![deny(missing_doc)]

#![reexport_test_harness_main = "test_main"]

// When testing libstd, bring in libuv as the I/O backend so tests can print
// things and all of the std::io tests have an I/O interface to run on top
// of
#[cfg(test)] extern crate rustuv;
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate green;
#[cfg(test)] extern crate debug;
#[cfg(test)] #[phase(plugin, link)] extern crate log;

extern crate alloc;
extern crate unicode;
extern crate core;
extern crate "collections" as core_collections;
extern crate "rand" as core_rand;
extern crate "sync" as core_sync;
extern crate libc;
extern crate rustrt;

// Make std testable by not duplicating lang items. See #2912
#[cfg(test)] extern crate "std" as realstd;
#[cfg(test)] pub use realstd::kinds;
#[cfg(test)] pub use realstd::ops;
#[cfg(test)] pub use realstd::cmp;
#[cfg(test)] pub use realstd::ty;
#[cfg(test)] pub use realstd::boxed;
#[cfg(test)] pub use realstd::gc;

// NB: These reexports are in the order they should be listed in rustdoc

pub use core::any;
pub use core::bool;
pub use core::cell;
pub use core::clone;
#[cfg(not(test))] pub use core::cmp;
pub use core::default;
pub use core::finally;
pub use core::intrinsics;
pub use core::iter;
#[cfg(not(test))] pub use core::kinds;
pub use core::mem;
#[cfg(not(test))] pub use core::ops;
pub use core::ptr;
pub use core::raw;
pub use core::simd;
pub use core::tuple;
// FIXME #15320: primitive documentation needs top-level modules, this
// should be `std::tuple::unit`.
pub use core::unit;
#[cfg(not(test))] pub use core::ty;
pub use core::result;
pub use core::option;

pub use alloc::boxed;
#[deprecated = "use boxed instead"]
pub use boxed as owned;

pub use alloc::rc;

pub use core_collections::slice;
pub use core_collections::str;
pub use core_collections::string;
pub use core_collections::vec;

pub use rustrt::c_str;
pub use rustrt::local_data;

pub use unicode::char;

pub use core_sync::comm;

// Run tests with libgreen instead of libnative.
#[cfg(test)] #[start]
fn start(argc: int, argv: *const *const u8) -> int {
    green::start(argc, argv, rustuv::event_loop, test_main)
}

/* Exported macros */

pub mod macros;
pub mod bitflags;

mod rtdeps;

/* The Prelude. */

pub mod prelude;

/* Primitive types */

#[path = "num/float_macros.rs"] mod float_macros;
#[path = "num/int_macros.rs"]   mod int_macros;
#[path = "num/uint_macros.rs"]  mod uint_macros;

#[path = "num/int.rs"]  pub mod int;
#[path = "num/i8.rs"]   pub mod i8;
#[path = "num/i16.rs"]  pub mod i16;
#[path = "num/i32.rs"]  pub mod i32;
#[path = "num/i64.rs"]  pub mod i64;

#[path = "num/uint.rs"] pub mod uint;
#[path = "num/u8.rs"]   pub mod u8;
#[path = "num/u16.rs"]  pub mod u16;
#[path = "num/u32.rs"]  pub mod u32;
#[path = "num/u64.rs"]  pub mod u64;

#[path = "num/f32.rs"]   pub mod f32;
#[path = "num/f64.rs"]   pub mod f64;

pub mod rand;

pub mod ascii;

#[cfg(not(test))]
pub mod gc;

pub mod time;

/* Common traits */

pub mod from_str;
pub mod num;
pub mod to_string;

/* Common data structures */

pub mod collections;
pub mod hash;

/* Tasks and communication */

pub mod task;
pub mod sync;

/* Runtime and platform support */

pub mod c_vec;
pub mod dynamic_lib;
pub mod os;
pub mod io;
pub mod path;
pub mod fmt;

// FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable'
// but name resolution doesn't work without it being pub.
pub mod rt;
mod failure;

// A curious inner-module that's not exported that contains the binding
// 'std' so that macro-expanded references to std::error and such
// can be resolved within libstd.
#[doc(hidden)]
mod std {
    // mods used for deriving
    pub use clone;
    pub use cmp;
    pub use hash;

    pub use comm; // used for select!()
    pub use fmt; // used for any formatting strings
    pub use io; // used for println!()
    pub use local_data; // used for local_data_key!()
    pub use option; // used for bitflags!{}
    pub use rt; // used for fail!()
    pub use vec; // used for vec![]

    // The test runner calls ::std::os::args() but really wants realstd
    #[cfg(test)] pub use realstd::os as os;
    // The test runner requires std::slice::Vector, so re-export std::slice just for it.
    #[cfg(test)] pub use slice;

    pub use collections; // vec!() uses MutableSeq
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use num::{FromPrimitive};

use log::{debug};
use failure::{Error};
use goblin::{Object};
use goblin::pe::section_table::SectionTable;

use super::super::util;
use super::super::arch::Arch;
use super::super::loader::{FileFormat, LoadedModule, Loader, Platform, Section, LoaderError, Permissions};
use super::super::analysis::{Analyzer};
use super::super::analysis::pe;

/// The section can be executed as code.
const IMAGE_SCN_MEM_EXECUTE: u32 = 0x20000000;

/// The section can be read.
const IMAGE_SCN_MEM_READ: u32 = 0x40000000;

/// The section can be written to.
const IMAGE_SCN_MEM_WRITE: u32 = 0x80000000;

pub struct PELoader<A: Arch> {
    // PELoader must have a type parameter for it
    //  to implement Loader<A>.
    // however, it doesn't actually use this type itself.
    // so, we use a phantom data marker which has zero type,
    //  to ensure there is not an unused type parameter,
    //  which is a compile error.
    _phantom: PhantomData<A>,
}

impl<A: Arch> PELoader<A> {
    pub fn new() -> PELoader<A> {
        PELoader {
            _phantom: PhantomData {},
        }
    }

    fn load_header(&self, buf: &[u8], pe: &goblin::pe::PE) -> Result<Section<A>, Error> {
        let hdr_raw_size = match pe.header.optional_header {
            Some(opt) => opt.windows_fields.size_of_headers,
            // assumption: header is at most 0x200 bytes.
            _ => 0x200,
        };

        //   on disk:
        //
        //   +---------------------------------+
        //   |   header        |  sections...  |
        //   +---------------------------------+
        //   .                  \
        //   .  in memory:       \
        //   .                    \
        //   +-----------------+---+        +-------------
        //   |   header        |   |        |  sections...
        //   +-----------------+---+        +-------------
        //                     ^   ^
        //                     |   +--- virtual size
        //                     |        aligned to 0x200
        //                     +-- raw size
        //                         no alignment

        let hdr_raw_size = std::cmp::min(hdr_raw_size as usize, buf.len());
        let hdr_virt_size = util::align(hdr_raw_size, 0x200);
        let mut headerbuf = vec![0; hdr_virt_size];
        {
            let rawbuf = &mut headerbuf[..hdr_raw_size];
            rawbuf.copy_from_slice(&buf[0x0..hdr_raw_size]);
        }

        Ok(Section {
            addr: A::RVA::from_u8(0x0).unwrap(),
            buf: headerbuf,
            perms: Permissions::R,
            name: String::from("header"),
        })
    }

    fn load_section(&self, buf: &[u8], section: &SectionTable) -> Result<Section<A>, Error> {
        let name = String::from_utf8_lossy(&section.name[..])
            .into_owned()
            .trim_end_matches("\u{0}")
            .trim_end()
            .to_string();

        // assumption: each section fits within one u32
        let virtual_size = util::align(section.virtual_size as usize, 0x200) as usize;
        let mut secbuf = vec![0; virtual_size as usize];

        {
            // in nop.exe, we have virtualsize=0x12FE and rawsize=0x2000.
            // this teaches us that we have to handle the case where rawsize > virtualsize.
            //
            // TODO: do we pick align(virtualsize, 0x200) or just virtualsize?
            let raw_size = std::cmp::min(section.virtual_size, section.size_of_raw_data);
            let rawbuf = &mut secbuf[..raw_size as usize];
            let pstart = section.pointer_to_raw_data as usize;
            let pend = pstart + raw_size as usize;
            rawbuf.copy_from_slice(&buf[pstart..pend]);
        }

        let mut perms = Permissions::empty();
        if section.characteristics & IMAGE_SCN_MEM_READ > 0 {
            perms.insert(Permissions::R);
        }
        if section.characteristics & IMAGE_SCN_MEM_WRITE > 0 {
            perms.insert(Permissions::W);
        }
        if section.characteristics & IMAGE_SCN_MEM_EXECUTE > 0 {
            perms.insert(Permissions::X);
        }

        Ok(Section{
            addr: A::RVA::from_u32(section.virtual_address).unwrap(),
            buf: secbuf,
            perms,
            name,
        })
    }
}

impl<A: Arch + 'static> Loader<A> for PELoader<A> {
    fn get_arch(&self) -> u8 {
        A::get_bits()
    }

    fn get_plat(&self) -> Platform {
        Platform::Windows
    }

    fn get_file_format(&self) -> FileFormat {
        FileFormat::PE
    }

    /// ```
    /// use lancelot::rsrc::*;
    /// use lancelot::arch::*;
    /// use lancelot::loader::*;
    ///
    /// let loader = lancelot::loaders::pe::PELoader::<Arch64>::new();
    /// assert_eq!(loader.taste(&get_buf(Rsrc::K32)), true);
    /// ```
    fn taste(&self, buf: &[u8]) -> bool {
        if let Ok(Object::PE(pe)) = Object::parse(buf) {
            if pe.is_64 && self.get_arch() == 32 {
                return false;
            }

            if !pe.is_64 && self.get_arch() == 64 {
                return false;
            }

            return true;
        } else {
            false
        }
    }

    /// ```
    /// use lancelot::rsrc::*;
    /// use lancelot::arch::*;
    /// use lancelot::loader::*;
    ///
    /// let loader = lancelot::loaders::pe::PELoader::<Arch64>::new();
    /// let (module, analyzers) = loader.load(&get_buf(Rsrc::K32)).unwrap();
    /// assert_eq!(module.base_address, 0x180000000);
    ///
    /// // mismatched bitness
    /// let loader = lancelot::loaders::pe::PELoader::<Arch32>::new();
    /// assert!(loader.load(&get_buf(Rsrc::K32)).is_err());
    /// ```
    fn load(&self, buf: &[u8]) -> Result<(LoadedModule<A>, Vec<Box<dyn Analyzer<A>>>), Error> {
        if let Ok(Object::PE(pe)) = Object::parse(buf) {
            if pe.is_64 && self.get_arch() == 32 {
                return Err(LoaderError::MismatchedBitness.into());
            }

            if !pe.is_64 && self.get_arch() == 64 {
                return Err(LoaderError::MismatchedBitness.into());
            }

            let base_address = match pe.header.optional_header {
                Some(opt) => opt.windows_fields.image_base,
                _ => {
                    debug!("using default base address: 0x40:000");
                    0x40_000
                }
            };

            let base_address = match A::VA::from_u64(base_address) {
                Some(base_address) => base_address,
                // this would only fail if there's a 64-bit base address in a 32-bit PE
                None => return Err(LoaderError::NotSupported.into()),
            };

            let mut sections = vec![self.load_header(buf, &pe)];
            sections.extend(pe.sections
                            .iter()
                            .map(|sec| self.load_section(buf, sec)));

            // collect sections into either list of sections, or error.
            //
            // via: https://doc.rust-lang.org/rust-by-example/error/iter_result.html
            match sections.into_iter().collect::<Result<Vec<Section<A>>, Error>>() {
                Ok(sections) => Ok(
                    (LoadedModule {
                        base_address,
                        sections,
                     },
                     vec![Box::new(pe::EntryPointAnalyzer::new()),
                          Box::new(pe::ExportsAnalyzer::new()),
                          Box::new(pe::ImportsAnalyzer::new()),
                     ])),
                Err(e) => Err(e),
            }
        } else {
            Err(LoaderError::NotSupported.into())
        }
    }
}
<commit_msg>pe loader: split section name at first NULL<commit_after>use std::marker::PhantomData;
use num::{FromPrimitive};

use log::{debug};
use failure::{Error};
use goblin::{Object};
use goblin::pe::section_table::SectionTable;

use super::super::util;
use super::super::arch::Arch;
use super::super::loader::{FileFormat, LoadedModule, Loader, Platform, Section, LoaderError, Permissions};
use super::super::analysis::{Analyzer};
use super::super::analysis::pe;

/// The section can be executed as code.
const IMAGE_SCN_MEM_EXECUTE: u32 = 0x20000000;

/// The section can be read.
const IMAGE_SCN_MEM_READ: u32 = 0x40000000;

/// The section can be written to.
const IMAGE_SCN_MEM_WRITE: u32 = 0x80000000;

pub struct PELoader<A: Arch> {
    // PELoader must have a type parameter for it
    //  to implement Loader<A>.
    // however, it doesn't actually use this type itself.
    // so, we use a phantom data marker which has zero type,
    //  to ensure there is not an unused type parameter,
    //  which is a compile error.
    _phantom: PhantomData<A>,
}

impl<A: Arch> PELoader<A> {
    pub fn new() -> PELoader<A> {
        PELoader {
            _phantom: PhantomData {},
        }
    }

    fn load_header(&self, buf: &[u8], pe: &goblin::pe::PE) -> Result<Section<A>, Error> {
        let hdr_raw_size = match pe.header.optional_header {
            Some(opt) => opt.windows_fields.size_of_headers,
            // assumption: header is at most 0x200 bytes.
            _ => 0x200,
        };

        //   on disk:
        //
        //   +---------------------------------+
        //   |   header        |  sections...  |
        //   +---------------------------------+
        //   .                  \
        //   .  in memory:       \
        //   .                    \
        //   +-----------------+---+        +-------------
        //   |   header        |   |        |  sections...
        //   +-----------------+---+        +-------------
        //                     ^   ^
        //                     |   +--- virtual size
        //                     |        aligned to 0x200
        //                     +-- raw size
        //                         no alignment

        let hdr_raw_size = std::cmp::min(hdr_raw_size as usize, buf.len());
        let hdr_virt_size = util::align(hdr_raw_size, 0x200);
        let mut headerbuf = vec![0; hdr_virt_size];
        {
            let rawbuf = &mut headerbuf[..hdr_raw_size];
            rawbuf.copy_from_slice(&buf[0x0..hdr_raw_size]);
        }

        Ok(Section {
            addr: A::RVA::from_u8(0x0).unwrap(),
            buf: headerbuf,
            perms: Permissions::R,
            name: String::from("header"),
        })
    }

    fn load_section(&self, buf: &[u8], section: &SectionTable) -> Result<Section<A>, Error> {
        let name = String::from_utf8_lossy(&section.name[..])
            .into_owned()
            .trim_end_matches("\u{0}")
            .trim_end()
            .splitn(2, "\u{0}")
            .next()
            .unwrap()
            .to_string();

        // assumption: each section fits within one u32
        let virtual_size = util::align(section.virtual_size as usize, 0x200) as usize;
        let mut secbuf = vec![0; virtual_size as usize];

        {
            // in nop.exe, we have virtualsize=0x12FE and rawsize=0x2000.
            // this teaches us that we have to handle the case where rawsize > virtualsize.
            //
            // TODO: do we pick align(virtualsize, 0x200) or just virtualsize?
            let raw_size = std::cmp::min(section.virtual_size, section.size_of_raw_data);
            let rawbuf = &mut secbuf[..raw_size as usize];
            let pstart = section.pointer_to_raw_data as usize;
            let pend = pstart + raw_size as usize;
            rawbuf.copy_from_slice(&buf[pstart..pend]);
        }

        let mut perms = Permissions::empty();
        if section.characteristics & IMAGE_SCN_MEM_READ > 0 {
            perms.insert(Permissions::R);
        }
        if section.characteristics & IMAGE_SCN_MEM_WRITE > 0 {
            perms.insert(Permissions::W);
        }
        if section.characteristics & IMAGE_SCN_MEM_EXECUTE > 0 {
            perms.insert(Permissions::X);
        }

        Ok(Section{
            addr: A::RVA::from_u32(section.virtual_address).unwrap(),
            buf: secbuf,
            perms,
            name,
        })
    }
}

impl<A: Arch + 'static> Loader<A> for PELoader<A> {
    fn get_arch(&self) -> u8 {
        A::get_bits()
    }

    fn get_plat(&self) -> Platform {
        Platform::Windows
    }

    fn get_file_format(&self) -> FileFormat {
        FileFormat::PE
    }

    /// ```
    /// use lancelot::rsrc::*;
    /// use lancelot::arch::*;
    /// use lancelot::loader::*;
    ///
    /// let loader = lancelot::loaders::pe::PELoader::<Arch64>::new();
    /// assert_eq!(loader.taste(&get_buf(Rsrc::K32)), true);
    /// ```
    fn taste(&self, buf: &[u8]) -> bool {
        if let Ok(Object::PE(pe)) = Object::parse(buf) {
            if pe.is_64 && self.get_arch() == 32 {
                return false;
            }

            if !pe.is_64 && self.get_arch() == 64 {
                return false;
            }

            return true;
        } else {
            false
        }
    }

    /// ```
    /// use lancelot::rsrc::*;
    /// use lancelot::arch::*;
    /// use lancelot::loader::*;
    ///
    /// let loader = lancelot::loaders::pe::PELoader::<Arch64>::new();
    /// let (module, analyzers) = loader.load(&get_buf(Rsrc::K32)).unwrap();
    /// assert_eq!(module.base_address, 0x180000000);
    ///
    /// // mismatched bitness
    /// let loader = lancelot::loaders::pe::PELoader::<Arch32>::new();
    /// assert!(loader.load(&get_buf(Rsrc::K32)).is_err());
    /// ```
    fn load(&self, buf: &[u8]) -> Result<(LoadedModule<A>, Vec<Box<dyn Analyzer<A>>>), Error> {
        if let Ok(Object::PE(pe)) = Object::parse(buf) {
            if pe.is_64 && self.get_arch() == 32 {
                return Err(LoaderError::MismatchedBitness.into());
            }

            if !pe.is_64 && self.get_arch() == 64 {
                return Err(LoaderError::MismatchedBitness.into());
            }

            let base_address = match pe.header.optional_header {
                Some(opt) => opt.windows_fields.image_base,
                _ => {
                    debug!("using default base address: 0x40:000");
                    0x40_000
                }
            };

            let base_address = match A::VA::from_u64(base_address) {
                Some(base_address) => base_address,
                // this would only fail if there's a 64-bit base address in a 32-bit PE
                None => return Err(LoaderError::NotSupported.into()),
            };

            let mut sections = vec![self.load_header(buf, &pe)];
            sections.extend(pe.sections
                            .iter()
                            .map(|sec| self.load_section(buf, sec)));

            // collect sections into either list of sections, or error.
            //
            // via: https://doc.rust-lang.org/rust-by-example/error/iter_result.html
            match sections.into_iter().collect::<Result<Vec<Section<A>>, Error>>() {
                Ok(sections) => Ok(
                    (LoadedModule {
                        base_address,
                        sections,
                     },
                     vec![Box::new(pe::EntryPointAnalyzer::new()),
                          Box::new(pe::ExportsAnalyzer::new()),
                          Box::new(pe::ImportsAnalyzer::new()),
                     ])),
                Err(e) => Err(e),
            }
        } else {
            Err(LoaderError::NotSupported.into())
        }
    }
}
<|endoftext|>


<commit_before>extern crate collections;
use collections::HashMap;

enum State {
	Clean,
	Dirty
}

struct BufferManager<'a> {
	size: uint,
	frames: HashMap<u64, BufferEntry<'a>>,
}

struct BufferEntry<'a> {
	state: State,
	frame: BufferFrame<'a>,
}

struct BufferFrame<'a> {
	data: &'a mut [u8],
}

impl<'a> BufferManager<'a> {
	pub fn new(size: uint) -> BufferManager {
		let h = HashMap::with_capacity(size);
		BufferManager {size: size, frames: h}
	}

	pub fn fixPage(pageId: u64, exclusive: bool) -> Option<BufferFrame> {
		None
	}

	pub fn unfixPage(frame: BufferFrame, isDirty: bool) {
	}
}

impl<'a> BufferFrame<'a> {
	pub fn getData() -> ~[u8] {
		~[0_u8, ..1024]
	}
}

fn main() {
	println!("Rewrite me into a test");
}
<commit_msg>Fixed up data model a bit<commit_after>extern crate collections;
use collections::HashMap;
use std::io::{File, Open, Read, Write, TempDir};

enum State {
	Available,
	Exclusive,
}

struct BufferManager {
	size: uint,
	entries: HashMap<u64, BufferEntry>,
	directory: TempDir,
}

struct BufferEntry {
	state: State,
	frame: BufferFrame,
}

struct BufferFrame {
	data: Vec<u8>,
}

impl BufferManager {
	pub fn new(size: uint) -> BufferManager {
		let h = HashMap::with_capacity(size);
		let dir = match TempDir::new("externalsort") {
			Some(temp_dir) => temp_dir,
			None => fail!("creation of temporary directory"),
		};
		BufferManager {size: size, entries: h, directory: dir}
	}

	fn openOrCreate(&self, pageId: u64) -> File {
		let page_path = self.directory.path();
		let file_path = page_path.join(pageId.to_str());
		let mut file_handle = match File::open_mode(&file_path, Open, Read) {
			Ok(f) => f,
			Err(e) => {
				match File::open_mode(&file_path, Open, Write) {
					Ok(mut f) => {
						f.write([0_u8, ..4 * 1024]);
						match File::open_mode(&file_path, Open, Read) {
							Ok(f) => f,
							Err(e) => fail!("failed reading file: {}, e"),
						}
					},
					Err(e) => fail!("Writing file failed: {}", e),
				}
			},
		};
		file_handle
	}

	fn loadPage(&mut self, pageId: u64) {
		if self.entries.len() == self.size {
			self.evictPage();
		}

		// TODO: open file, load page
		let mut file_handle = self.openOrCreate(pageId);
		let buffer = [0_u8, ..4*1024];

		let content = match file_handle.read_exact(4*1024) {
			Ok(c) => Vec::from_slice(c),
			Err(e) => fail!("Couldn't read from page: {}", e),
		};

		let frame = BufferFrame {data: content};
		let entry = BufferEntry {state: Available, frame: frame};
		self.entries.insert(pageId, entry);
	}

	fn evictPage(&mut self) {
		// TODO delete a random page
	}

	pub fn fixPage(pageId: u64, exclusive: bool) -> Option<BufferFrame> {
		// TODO
		None
	}

	pub fn unfixPage(frame: BufferFrame, isDirty: bool) {
		// TODO
	}
}

impl BufferFrame {
	pub fn getData<'a>(&'a mut self) -> &'a mut [u8] {
		self.data.as_mut_slice()
	}
}

fn main() {
	println!("Rewrite me into a test");
}
<|endoftext|>


<commit_before>//! Fully type-check project and print various stats, like the number of type
//! errors.

use std::{
    path::Path,
    time::{SystemTime, UNIX_EPOCH},
};

use hir::{
    db::{AstDatabase, DefDatabase, HirDatabase},
    original_range, AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
};
use hir_def::FunctionId;
use hir_ty::{Ty, TypeWalk};
use itertools::Itertools;
use oorandom::Rand32;
use ra_db::{
    salsa::{self, ParallelDatabase},
    SourceDatabaseExt,
};
use ra_syntax::AstNode;
use rayon::prelude::*;
use rustc_hash::FxHashSet;
use stdx::format_to;

use crate::{
    cli::{
        load_cargo::load_cargo, progress_report::ProgressReport, report_metric, Result, Verbosity,
    },
    print_memory_usage,
};
use ra_prof::StopWatch;

/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
struct Snap<DB>(DB);
impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
    fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
        Snap(self.0.snapshot())
    }
}

pub fn analysis_stats(
    verbosity: Verbosity,
    memory_usage: bool,
    path: &Path,
    only: Option<&str>,
    with_deps: bool,
    randomize: bool,
    parallel: bool,
    load_output_dirs: bool,
    with_proc_macro: bool,
) -> Result<()> {
    let mut rng = {
        let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64;
        Rand32::new(seed)
    };

    let mut db_load_sw = StopWatch::start().memory(memory_usage);
    let (host, vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?;
    let db = host.raw_database();
    eprintln!("Database loaded {}", db_load_sw.elapsed());

    let mut analysis_sw = StopWatch::start().memory(memory_usage);
    let mut num_crates = 0;
    let mut visited_modules = FxHashSet::default();
    let mut visit_queue = Vec::new();

    let mut krates = Crate::all(db);
    if randomize {
        shuffle(&mut rng, &mut krates);
    }
    for krate in krates {
        let module = krate.root_module(db).expect("crate without root module");
        let file_id = module.definition_source(db).file_id;
        let file_id = file_id.original_file(db);
        let source_root = db.file_source_root(file_id);
        let source_root = db.source_root(source_root);
        if !source_root.is_library || with_deps {
            num_crates += 1;
            visit_queue.push(module);
        }
    }

    if randomize {
        shuffle(&mut rng, &mut visit_queue);
    }

    eprintln!("Crates in this dir: {}", num_crates);
    let mut num_decls = 0;
    let mut funcs = Vec::new();
    while let Some(module) = visit_queue.pop() {
        if visited_modules.insert(module) {
            visit_queue.extend(module.children(db));

            for decl in module.declarations(db) {
                num_decls += 1;
                if let ModuleDef::Function(f) = decl {
                    funcs.push(f);
                }
            }

            for impl_def in module.impl_defs(db) {
                for item in impl_def.items(db) {
                    num_decls += 1;
                    if let AssocItem::Function(f) = item {
                        funcs.push(f);
                    }
                }
            }
        }
    }
    eprintln!("Total modules found: {}", visited_modules.len());
    eprintln!("Total declarations: {}", num_decls);
    eprintln!("Total functions: {}", funcs.len());
    eprintln!("Item Collection: {}", analysis_sw.elapsed());

    if randomize {
        shuffle(&mut rng, &mut funcs);
    }

    let mut bar = match verbosity {
        Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
        _ if parallel => ProgressReport::hidden(),
        _ => ProgressReport::new(funcs.len() as u64),
    };

    if parallel {
        let mut inference_sw = StopWatch::start().memory(memory_usage);
        let snap = Snap(db.snapshot());
        funcs
            .par_iter()
            .map_with(snap, |snap, &f| {
                let f_id = FunctionId::from(f);
                snap.0.body(f_id.into());
                snap.0.infer(f_id.into());
            })
            .count();
        eprintln!("Parallel Inference: {}", inference_sw.elapsed());
    }

    let mut inference_sw = StopWatch::start().memory(memory_usage);
    bar.tick();
    let mut num_exprs = 0;
    let mut num_exprs_unknown = 0;
    let mut num_exprs_partially_unknown = 0;
    let mut num_type_mismatches = 0;
    for f in funcs {
        let name = f.name(db);
        let full_name = f
            .module(db)
            .path_to_root(db)
            .into_iter()
            .rev()
            .filter_map(|it| it.name(db))
            .chain(Some(f.name(db)))
            .join("::");
        if let Some(only_name) = only {
            if name.to_string() != only_name && full_name != only_name {
                continue;
            }
        }
        let mut msg = format!("processing: {}", full_name);
        if verbosity.is_verbose() {
            let src = f.source(db);
            let original_file = src.file_id.original_file(db);
            let path = vfs.file_path(original_file);
            let syntax_range = src.value.syntax().text_range();
            format_to!(msg, " ({} {:?})", path, syntax_range);
        }
        if verbosity.is_spammy() {
            bar.println(msg.to_string());
        }
        bar.set_message(&msg);
        let f_id = FunctionId::from(f);
        let body = db.body(f_id.into());
        let inference_result = db.infer(f_id.into());
        let (previous_exprs, previous_unknown, previous_partially_unknown) =
            (num_exprs, num_exprs_unknown, num_exprs_partially_unknown);
        for (expr_id, _) in body.exprs.iter() {
            let ty = &inference_result[expr_id];
            num_exprs += 1;
            if let Ty::Unknown = ty {
                num_exprs_unknown += 1;
            } else {
                let mut is_partially_unknown = false;
                ty.walk(&mut |ty| {
                    if let Ty::Unknown = ty {
                        is_partially_unknown = true;
                    }
                });
                if is_partially_unknown {
                    num_exprs_partially_unknown += 1;
                }
            }
            if only.is_some() && verbosity.is_spammy() {
                // in super-verbose mode for just one function, we print every single expression
                let (_, sm) = db.body_with_source_map(f_id.into());
                let src = sm.expr_syntax(expr_id);
                if let Ok(src) = src {
                    let node = {
                        let root = db.parse_or_expand(src.file_id).unwrap();
                        src.value.to_node(&root)
                    };
                    let original_file = src.file_id.original_file(db);
                    let line_index = host.analysis().file_line_index(original_file).unwrap();
                    let text_range = node.syntax().text_range();
                    let (start, end) = (
                        line_index.line_col(text_range.start()),
                        line_index.line_col(text_range.end()),
                    );
                    bar.println(format!(
                        "{}:{}-{}:{}: {}",
                        start.line + 1,
                        start.col_utf16,
                        end.line + 1,
                        end.col_utf16,
                        ty.display(db)
                    ));
                } else {
                    bar.println(format!("unknown location: {}", ty.display(db)));
                }
            }
            if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
                num_type_mismatches += 1;
                if verbosity.is_verbose() {
                    let (_, sm) = db.body_with_source_map(f_id.into());
                    let src = sm.expr_syntax(expr_id);
                    if let Ok(src) = src {
                        // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
                        // But also, we should just turn the type mismatches into diagnostics and provide these
                        let root = db.parse_or_expand(src.file_id).unwrap();
                        let node = src.map(|e| e.to_node(&root).syntax().clone());
                        let original_range = original_range(db, node.as_ref());
                        let path = vfs.file_path(original_range.file_id);
                        let line_index =
                            host.analysis().file_line_index(original_range.file_id).unwrap();
                        let text_range = original_range.range;
                        let (start, end) = (
                            line_index.line_col(text_range.start()),
                            line_index.line_col(text_range.end()),
                        );
                        bar.println(format!(
                            "{} {}:{}-{}:{}: Expected {}, got {}",
                            path,
                            start.line + 1,
                            start.col_utf16,
                            end.line + 1,
                            end.col_utf16,
                            mismatch.expected.display(db),
                            mismatch.actual.display(db)
                        ));
                    } else {
                        bar.println(format!(
                            "{}: Expected {}, got {}",
                            name,
                            mismatch.expected.display(db),
                            mismatch.actual.display(db)
                        ));
                    }
                }
            }
        }
        if verbosity.is_spammy() {
            bar.println(format!(
                "In {}: {} exprs, {} unknown, {} partial",
                full_name,
                num_exprs - previous_exprs,
                num_exprs_unknown - previous_unknown,
                num_exprs_partially_unknown - previous_partially_unknown
            ));
        }
        bar.inc(1);
    }
    bar.finish_and_clear();
    eprintln!("Total expressions: {}", num_exprs);
    eprintln!(
        "Expressions of unknown type: {} ({}%)",
        num_exprs_unknown,
        if num_exprs > 0 { num_exprs_unknown * 100 / num_exprs } else { 100 }
    );
    report_metric("unknown type", num_exprs_unknown, "#");

    eprintln!(
        "Expressions of partially unknown type: {} ({}%)",
        num_exprs_partially_unknown,
        if num_exprs > 0 { num_exprs_partially_unknown * 100 / num_exprs } else { 100 }
    );

    eprintln!("Type mismatches: {}", num_type_mismatches);
    report_metric("type mismatches", num_type_mismatches, "#");

    eprintln!("Inference: {}", inference_sw.elapsed());

    let total_span = analysis_sw.elapsed();
    eprintln!("Total: {}", total_span);
    report_metric("total time", total_span.time.as_millis() as u64, "ms");
    if let Some(instructions) = total_span.instructions {
        report_metric("total time", instructions, "#instr");
    }
    if let Some(memory) = total_span.memory {
        report_metric("total memory", memory.allocated.megabytes() as u64, "MB");
    }

    if memory_usage {
        print_memory_usage(host, vfs);
    }

    Ok(())
}

fn shuffle<T>(rng: &mut Rand32, slice: &mut [T]) {
    for i in (1..slice.len()).rev() {
        let idx = rng.rand_range(0..i as u32) as usize;
        slice.swap(idx, i)
    }
}
<commit_msg>Rename metric<commit_after>//! Fully type-check project and print various stats, like the number of type
//! errors.

use std::{
    path::Path,
    time::{SystemTime, UNIX_EPOCH},
};

use hir::{
    db::{AstDatabase, DefDatabase, HirDatabase},
    original_range, AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
};
use hir_def::FunctionId;
use hir_ty::{Ty, TypeWalk};
use itertools::Itertools;
use oorandom::Rand32;
use ra_db::{
    salsa::{self, ParallelDatabase},
    SourceDatabaseExt,
};
use ra_syntax::AstNode;
use rayon::prelude::*;
use rustc_hash::FxHashSet;
use stdx::format_to;

use crate::{
    cli::{
        load_cargo::load_cargo, progress_report::ProgressReport, report_metric, Result, Verbosity,
    },
    print_memory_usage,
};
use ra_prof::StopWatch;

/// Need to wrap Snapshot to provide `Clone` impl for `map_with`
struct Snap<DB>(DB);
impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
    fn clone(&self) -> Snap<salsa::Snapshot<DB>> {
        Snap(self.0.snapshot())
    }
}

pub fn analysis_stats(
    verbosity: Verbosity,
    memory_usage: bool,
    path: &Path,
    only: Option<&str>,
    with_deps: bool,
    randomize: bool,
    parallel: bool,
    load_output_dirs: bool,
    with_proc_macro: bool,
) -> Result<()> {
    let mut rng = {
        let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() as u64;
        Rand32::new(seed)
    };

    let mut db_load_sw = StopWatch::start().memory(memory_usage);
    let (host, vfs) = load_cargo(path, load_output_dirs, with_proc_macro)?;
    let db = host.raw_database();
    eprintln!("Database loaded {}", db_load_sw.elapsed());

    let mut analysis_sw = StopWatch::start().memory(memory_usage);
    let mut num_crates = 0;
    let mut visited_modules = FxHashSet::default();
    let mut visit_queue = Vec::new();

    let mut krates = Crate::all(db);
    if randomize {
        shuffle(&mut rng, &mut krates);
    }
    for krate in krates {
        let module = krate.root_module(db).expect("crate without root module");
        let file_id = module.definition_source(db).file_id;
        let file_id = file_id.original_file(db);
        let source_root = db.file_source_root(file_id);
        let source_root = db.source_root(source_root);
        if !source_root.is_library || with_deps {
            num_crates += 1;
            visit_queue.push(module);
        }
    }

    if randomize {
        shuffle(&mut rng, &mut visit_queue);
    }

    eprintln!("Crates in this dir: {}", num_crates);
    let mut num_decls = 0;
    let mut funcs = Vec::new();
    while let Some(module) = visit_queue.pop() {
        if visited_modules.insert(module) {
            visit_queue.extend(module.children(db));

            for decl in module.declarations(db) {
                num_decls += 1;
                if let ModuleDef::Function(f) = decl {
                    funcs.push(f);
                }
            }

            for impl_def in module.impl_defs(db) {
                for item in impl_def.items(db) {
                    num_decls += 1;
                    if let AssocItem::Function(f) = item {
                        funcs.push(f);
                    }
                }
            }
        }
    }
    eprintln!("Total modules found: {}", visited_modules.len());
    eprintln!("Total declarations: {}", num_decls);
    eprintln!("Total functions: {}", funcs.len());
    eprintln!("Item Collection: {}", analysis_sw.elapsed());

    if randomize {
        shuffle(&mut rng, &mut funcs);
    }

    let mut bar = match verbosity {
        Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
        _ if parallel => ProgressReport::hidden(),
        _ => ProgressReport::new(funcs.len() as u64),
    };

    if parallel {
        let mut inference_sw = StopWatch::start().memory(memory_usage);
        let snap = Snap(db.snapshot());
        funcs
            .par_iter()
            .map_with(snap, |snap, &f| {
                let f_id = FunctionId::from(f);
                snap.0.body(f_id.into());
                snap.0.infer(f_id.into());
            })
            .count();
        eprintln!("Parallel Inference: {}", inference_sw.elapsed());
    }

    let mut inference_sw = StopWatch::start().memory(memory_usage);
    bar.tick();
    let mut num_exprs = 0;
    let mut num_exprs_unknown = 0;
    let mut num_exprs_partially_unknown = 0;
    let mut num_type_mismatches = 0;
    for f in funcs {
        let name = f.name(db);
        let full_name = f
            .module(db)
            .path_to_root(db)
            .into_iter()
            .rev()
            .filter_map(|it| it.name(db))
            .chain(Some(f.name(db)))
            .join("::");
        if let Some(only_name) = only {
            if name.to_string() != only_name && full_name != only_name {
                continue;
            }
        }
        let mut msg = format!("processing: {}", full_name);
        if verbosity.is_verbose() {
            let src = f.source(db);
            let original_file = src.file_id.original_file(db);
            let path = vfs.file_path(original_file);
            let syntax_range = src.value.syntax().text_range();
            format_to!(msg, " ({} {:?})", path, syntax_range);
        }
        if verbosity.is_spammy() {
            bar.println(msg.to_string());
        }
        bar.set_message(&msg);
        let f_id = FunctionId::from(f);
        let body = db.body(f_id.into());
        let inference_result = db.infer(f_id.into());
        let (previous_exprs, previous_unknown, previous_partially_unknown) =
            (num_exprs, num_exprs_unknown, num_exprs_partially_unknown);
        for (expr_id, _) in body.exprs.iter() {
            let ty = &inference_result[expr_id];
            num_exprs += 1;
            if let Ty::Unknown = ty {
                num_exprs_unknown += 1;
            } else {
                let mut is_partially_unknown = false;
                ty.walk(&mut |ty| {
                    if let Ty::Unknown = ty {
                        is_partially_unknown = true;
                    }
                });
                if is_partially_unknown {
                    num_exprs_partially_unknown += 1;
                }
            }
            if only.is_some() && verbosity.is_spammy() {
                // in super-verbose mode for just one function, we print every single expression
                let (_, sm) = db.body_with_source_map(f_id.into());
                let src = sm.expr_syntax(expr_id);
                if let Ok(src) = src {
                    let node = {
                        let root = db.parse_or_expand(src.file_id).unwrap();
                        src.value.to_node(&root)
                    };
                    let original_file = src.file_id.original_file(db);
                    let line_index = host.analysis().file_line_index(original_file).unwrap();
                    let text_range = node.syntax().text_range();
                    let (start, end) = (
                        line_index.line_col(text_range.start()),
                        line_index.line_col(text_range.end()),
                    );
                    bar.println(format!(
                        "{}:{}-{}:{}: {}",
                        start.line + 1,
                        start.col_utf16,
                        end.line + 1,
                        end.col_utf16,
                        ty.display(db)
                    ));
                } else {
                    bar.println(format!("unknown location: {}", ty.display(db)));
                }
            }
            if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
                num_type_mismatches += 1;
                if verbosity.is_verbose() {
                    let (_, sm) = db.body_with_source_map(f_id.into());
                    let src = sm.expr_syntax(expr_id);
                    if let Ok(src) = src {
                        // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
                        // But also, we should just turn the type mismatches into diagnostics and provide these
                        let root = db.parse_or_expand(src.file_id).unwrap();
                        let node = src.map(|e| e.to_node(&root).syntax().clone());
                        let original_range = original_range(db, node.as_ref());
                        let path = vfs.file_path(original_range.file_id);
                        let line_index =
                            host.analysis().file_line_index(original_range.file_id).unwrap();
                        let text_range = original_range.range;
                        let (start, end) = (
                            line_index.line_col(text_range.start()),
                            line_index.line_col(text_range.end()),
                        );
                        bar.println(format!(
                            "{} {}:{}-{}:{}: Expected {}, got {}",
                            path,
                            start.line + 1,
                            start.col_utf16,
                            end.line + 1,
                            end.col_utf16,
                            mismatch.expected.display(db),
                            mismatch.actual.display(db)
                        ));
                    } else {
                        bar.println(format!(
                            "{}: Expected {}, got {}",
                            name,
                            mismatch.expected.display(db),
                            mismatch.actual.display(db)
                        ));
                    }
                }
            }
        }
        if verbosity.is_spammy() {
            bar.println(format!(
                "In {}: {} exprs, {} unknown, {} partial",
                full_name,
                num_exprs - previous_exprs,
                num_exprs_unknown - previous_unknown,
                num_exprs_partially_unknown - previous_partially_unknown
            ));
        }
        bar.inc(1);
    }
    bar.finish_and_clear();
    eprintln!("Total expressions: {}", num_exprs);
    eprintln!(
        "Expressions of unknown type: {} ({}%)",
        num_exprs_unknown,
        if num_exprs > 0 { num_exprs_unknown * 100 / num_exprs } else { 100 }
    );
    report_metric("unknown type", num_exprs_unknown, "#");

    eprintln!(
        "Expressions of partially unknown type: {} ({}%)",
        num_exprs_partially_unknown,
        if num_exprs > 0 { num_exprs_partially_unknown * 100 / num_exprs } else { 100 }
    );

    eprintln!("Type mismatches: {}", num_type_mismatches);
    report_metric("type mismatches", num_type_mismatches, "#");

    eprintln!("Inference: {}", inference_sw.elapsed());

    let total_span = analysis_sw.elapsed();
    eprintln!("Total: {}", total_span);
    report_metric("total time", total_span.time.as_millis() as u64, "ms");
    if let Some(instructions) = total_span.instructions {
        report_metric("total instructions", instructions, "#instr");
    }
    if let Some(memory) = total_span.memory {
        report_metric("total memory", memory.allocated.megabytes() as u64, "MB");
    }

    if memory_usage {
        print_memory_usage(host, vfs);
    }

    Ok(())
}

fn shuffle<T>(rng: &mut Rand32, slice: &mut [T]) {
    for i in (1..slice.len()).rev() {
        let idx = rng.rand_range(0..i as u32) as usize;
        slice.swap(idx, i)
    }
}
<|endoftext|>