1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
//! Miscellaneous functions used by different modules of the fuzzer.

use std::arch::asm;

// -----------------------------------------------------------------------------------------------
// Code ranges

/// A range of virtual addresses that contains instructions.
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct CodeRange(pub(crate) std::ops::Range<u64>);

impl CodeRange {
    /// Creates a new code range.
    ///
    /// Since we can't just instrument everything, because of data sections found in code ranges
    /// that could be interpreted as instructions. The user is responsible for identifying which
    /// ranges are actual code ranges.
    pub fn new(start: u64, end: u64) -> Self {
        Self(start..end)
    }
}

// -----------------------------------------------------------------------------------------------
// Random generator

/// Random number generator based on the xorshift algorithm.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct Random {
    /// The seed used for random generation.
    seed: u64,
}

impl Random {
    /// Set of alphanumeric characters that can be used when generating random strings.
    const ALPHANUM: &'static str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    /// Creates a new random number generator.
    #[inline]
    pub fn new(seed: u64) -> Self {
        assert_ne!(seed, 0);
        Self { seed }
    }

    /// Splits the current random number generator into a second one in a deterministic manner.
    #[inline]
    pub fn split(&mut self) -> Self {
        Self::new(self.u64() ^ 0x43e47ca448538d19)
    }

    /// Updates the PRNG's internal seed.
    #[inline]
    fn update(&mut self) {
        self.seed ^= self.seed << 13;
        self.seed ^= self.seed >> 7;
        self.seed ^= self.seed << 17;
    }

    /// Retrieves the PRNG's state without updating it.
    #[inline]
    pub fn get_state(&self) -> u64 {
        self.seed
    }

    /// Generates a random `u64` using a uniform distribution.
    #[inline]
    pub fn u64(&mut self) -> u64 {
        self.update();
        self.seed
    }

    /// Generates a random `u64` in the range `[start; end[` using a uniform distribution.
    #[inline]
    pub fn u64_range(&mut self, start: u64, end: u64) -> Option<u64> {
        self.update();
        Some(start + self.seed % end.checked_sub(start)?)
    }

    /// Generates a random `u64` in the range `[start; end[` using an exponential distribution.
    // TODO: check start and end, make sure they are valid.
    #[inline]
    pub fn exp_range(&mut self, start: u64, end: u64) -> Option<u64> {
        self.update();
        let (start, end) = (start as f64, end as f64);
        let rand = start + (end - start) * self.seed as f64 / u64::MAX as f64;
        let (exp_start, exp_end, exp_rand) = (
            (-start / 10.0).exp(),
            (-end / 10.0).exp(),
            (-rand / 10.0).exp(),
        );
        let res = start + (end - start) * (exp_rand - exp_end) / (exp_start - exp_end);
        Some(res as u64)
    }

    /// Generates a random alphanumeric string of length `len`.
    pub fn str(&mut self, len: usize) -> String {
        (0..len).step_by(8).fold(String::new(), |s, i| {
            let size = std::cmp::min(8, len - i);
            let random = self.u64();
            (0..size).fold(s, |mut t, j| {
                let idx = ((random >> j) & 0xff) % Self::ALPHANUM.len() as u64;
                let c = Self::ALPHANUM.as_bytes()[idx as usize] as char;
                t.push(c);
                t
            })
        })
    }

    /// Generates a random vector of bytes of length `len`.
    #[allow(clippy::uninit_vec)]
    #[inline]
    pub fn bytes(&mut self, len: usize) -> Vec<u8> {
        // let len = if len % 8 != 0 { len + (8 - len % 8) } else { len };
        let mut v = Vec::with_capacity(len);
        // SAFETY: we can directly set the length, since the allocation is large enough and
        //         we fill the vector entirely, so no unitialized values will leak.
        unsafe { v.set_len(len) };
        (0..len).step_by(8).fold(v, |mut v, i| {
            let size = std::cmp::min(8, len - i);
            let random = self.u64();
            v[i..i + size].copy_from_slice(&random.to_le_bytes()[..size]);
            v
        })
    }

    /// Generates a random vector of bytes of length `len`.
    #[inline]
    pub fn bytes_into_slice(&mut self, slice: &mut [u8], offset: usize, len: usize) {
        for i in (offset..offset + len).step_by(8) {
            let size = std::cmp::min(8, offset + len - i);
            slice[i..i + size].copy_from_slice(&self.u64().to_le_bytes()[..size]);
        }
    }

    /// Crates an iterator yielding random bytes.
    #[inline]
    pub fn bytes_iter(&mut self) -> RandomBytesIterator {
        RandomBytesIterator {
            rand: self.split(),
            current: [0u8; 8],
            offset: 0,
        }
    }
}

/// Iterator yielding random bytes.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct RandomBytesIterator {
    /// The iterator's PRNG.
    rand: Random,
    /// Array from which random bytes are yielded. It contains 8 random bytes and is refilled
    /// once all values have been used.
    current: [u8; 8],
    /// The current offset in the random bytes array.
    offset: usize,
}

impl Iterator for RandomBytesIterator {
    type Item = u8;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        if self.offset % 8 == 0 {
            self.offset = 0;
            self.current = self.rand.u64().to_le_bytes();
        }
        let b = self.current[self.offset % 8];
        self.offset += 1;
        Some(b)
    }
}

// -----------------------------------------------------------------------------------------------
// Misc functions

/// A fast log2 implementation for `usize` equivalent to `(x as f64).log2().ceil()`.
#[inline]
pub fn log2(x: usize) -> usize {
    let (orig_x, mut x, mut log) = (x, x, 0);
    while x != 0 {
        x >>= 1;
        log += 1;
    }
    log - 1 + ((orig_x & (orig_x - 1)) != 0) as usize
}

/// A fast log2 implementation for `usize` equivalent to `(x as f64).log2().floor()`.
#[inline]
pub fn log2_floor(x: usize) -> usize {
    let mut x = x;
    let mut log = 0;
    while x != 0 {
        x >>= 1;
        log += 1;
    }
    log - 1_usize
}

/// Returns the value of the Counter-timer Physical Count register (CNTPCT_EL0).
#[inline]
pub fn get_phys_counter() -> u64 {
    let mut count;
    unsafe {
        asm!(
            "mrs {}, cntpct_el0",
            out(reg) count
        );
    }
    count
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;

    #[test]
    fn utils_random_u64() {
        let mut rand = Random::new(0xa5a5a5a5a5a5a5);
        assert_eq!(
            (0..1000)
                .map(|_| rand.u64())
                .collect::<HashSet<u64>>()
                .len(),
            1000
        );
    }

    #[test]
    fn utils_random_range() {
        let mut rand = Random::new(0xa5a5a5a5a5a5a5);
        assert_eq!(
            (0..1000).all(|_| {
                let r = rand.u64_range(123, 456).unwrap();
                123 <= r && r < 456
            }),
            true
        );
    }

    #[test]
    fn utils_random_exp_range() {
        let mut rand = Random::new(0xa5a5a5a5a5a5a5);
        let mut distribution = [0; 100];
        (0..10000000).for_each(|_| {
            let r = rand.exp_range(0, distribution.len() as u64).unwrap();
            distribution[r as usize] += 1;
        });
        println!("{:?}", distribution);
    }

    #[test]
    fn utils_random_strings() {
        let mut rand = Random::new(0xa5a5a5a5a5a5a5);
        assert_eq!(
            (0..1000)
                .map(|_| rand.str(100))
                .collect::<HashSet<String>>()
                .len(),
            1000
        );
    }

    #[test]
    fn utils_random_bytes_iter() {
        let mut rand = Random::new(0xa5a5a5a5a5a5a5);
        println!("{:?}", rand.bytes_iter().take(25).collect::<Vec<u8>>());
        println!("{:?}", rand.bytes_iter().take(25).collect::<Vec<u8>>());
        println!("{:?}", rand.bytes_iter().take(25).collect::<Vec<u8>>());
        println!("{:?}", rand.bytes_iter().take(25).collect::<Vec<u8>>());
        println!("{:?}", rand.bytes_iter().take(25).collect::<Vec<u8>>());
        assert_eq!(
            (0..1000)
                .map(|_| rand.bytes_iter().take(10).collect::<Vec<u8>>())
                .collect::<HashSet<Vec<u8>>>()
                .len(),
            1000
        );
    }
}