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
use crate::packet::PtPacketParseError;
/// Cycle Count (CYC) packet.
#[derive(Debug, PartialEq, Clone)]
pub struct Cyc {
raw: [u8; 15], // according to Intel's libipt max len 15, SDM says: "The size of the counter is implementation specific"
len: usize,
}
impl Cyc {
/// Returns the encoded packet size in bytes.
pub const fn original_size(&self) -> usize {
self.len
}
}
impl Cyc {
// pub fn cycle_counter(&self) -> u64 {
// let mut counter = (self.raw[0] >> 3) as u64;
//
// for i in 1..self.len {
// counter |= ((self.raw[i] & 0xfe) as u64) << 4 << (7 * (i - 1));
// }
//
// counter
// }
/// Caller must check the header
///
/// Panics if input len is 0
#[inline]
pub(super) fn try_from_payload(input: &[u8]) -> Result<Self, PtPacketParseError> {
let mut raw = [input[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
let mut len = 1;
if input[0] & 0x04 != 0 {
loop {
len += 1;
if input.len() < len || raw.len() < len {
return Err(PtPacketParseError::MalformedPacket);
}
raw[len - 1] = input[len - 1];
if input[len - 1] & 0x01 == 0 {
break;
}
}
};
Ok(Self { raw, len })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cyc_original_size() {
let raws = [
[0b1111_1011u8].as_slice(),
[0b1111_1111u8, 0].as_slice(),
[0b1111_1111u8, 0b1, 0].as_slice(),
[0b1111_1111u8, 0b1010_1011, 0b1111_1110].as_slice(),
[0b111u8, 0b1, 0b1, 0b1, 0b1, 0b10].as_slice(),
// longest counter that fits in `Cyc::raw`
[
0b1111_1111u8,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b0,
]
.as_slice(),
];
for raw in raws {
let p = Cyc::try_from_payload(raw).unwrap();
assert_eq!(p.original_size(), raw.len(), "{raw:x?}");
assert_eq!(&p.raw[..p.original_size()], raw, "{raw:x?}");
}
let malformed = [
// the header announces a counter payload, but the buffer ends right after it
[0b0000_0111u8].as_slice(),
// the counter continues past the end of the buffer
[0b1111_1111u8, 0b1, 0b1].as_slice(),
// the counter is longer than the 15 bytes `Cyc::raw` can hold
[
0b1111_1111u8,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b1,
0b0,
]
.as_slice(),
];
for raw in malformed {
assert_eq!(
Cyc::try_from_payload(raw),
Err(PtPacketParseError::MalformedPacket),
"{raw:x?}"
);
}
}
// #[test]
// fn cycle_counter() {
// let raws = [
// ([0b1111_1011u8].as_slice(), 0x1f),
// ([0b1111_1111u8, 0].as_slice(), 0x1f),
// ([0b1111_1111u8, 0b10].as_slice(), 0x3f),
// ];
//
// for (raw, right) in raws {
// let p = Cyc::try_from_payload(raw).unwrap();
// assert_eq!(p.cycle_counter(), right);
// }
// }
}