Skip to content

Commit 945e10e

Browse files
committed
+ unit tests, changed ownership to ref on drop types
1 parent 7b0ac43 commit 945e10e

File tree

3 files changed

+167
-31
lines changed

3 files changed

+167
-31
lines changed

src/image/image.rs

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use libipt_sys::{
2929
#[cfg(test)]
3030
mod test {
3131
use super::*;
32+
use std::path::PathBuf;
3233

3334
// not much to test for in the unit tests
3435
// the integration tests should have way more stuffs
@@ -46,6 +47,82 @@ mod test {
4647
let i = Image::new(None).unwrap();
4748
assert!(i.name().is_none());
4849
}
50+
51+
fn img_with_file<'a>() -> Image<'a> {
52+
let file: PathBuf = [
53+
env!("CARGO_MANIFEST_DIR"), "testfiles", "garbage.txt"
54+
].iter().collect();
55+
56+
let mut i = Image::new(None).unwrap();
57+
let asid = Asid::new(Some(1), Some(2));
58+
i.add_file(file.to_str().unwrap(), 3, 10, Some(asid), 0x123)
59+
.unwrap();
60+
i
61+
}
62+
63+
#[test]
64+
fn test_img_file() {
65+
img_with_file();
66+
}
67+
68+
#[test]
69+
fn test_img_remove_filename() {
70+
let file: PathBuf = [
71+
env!("CARGO_MANIFEST_DIR"), "testfiles", "garbage.txt"
72+
].iter().collect();
73+
74+
assert_eq!(
75+
img_with_file()
76+
.remove_by_filename(file.to_str().unwrap(),
77+
Asid::new(Some(1), Some(2)))
78+
.unwrap(),
79+
1
80+
);
81+
}
82+
83+
#[test]
84+
fn test_img_remove_asid() {
85+
assert_eq!(
86+
img_with_file()
87+
.remove_by_asid(Asid::new(Some(1), Some(2)))
88+
.unwrap(),
89+
1
90+
);
91+
}
92+
93+
#[test]
94+
fn test_img_copy() {
95+
let file: PathBuf = [
96+
env!("CARGO_MANIFEST_DIR"), "testfiles", "garbage.txt"
97+
].iter().collect();
98+
99+
let mut i = Image::new(None).unwrap();
100+
let asid = Asid::new(Some(3), Some(4));
101+
i.add_file(file.to_str().unwrap(), 3, 10, Some(asid), 0x666)
102+
.unwrap();
103+
104+
assert_eq!(
105+
img_with_file().copy(&i).unwrap(),
106+
1
107+
)
108+
}
109+
110+
#[test]
111+
fn test_img_add_cached() {
112+
let file: PathBuf = [
113+
env!("CARGO_MANIFEST_DIR"), "testfiles", "garbage.txt"
114+
].iter().collect();
115+
println!("{:?}", file);
116+
117+
let mut c = SectionCache::new(None).unwrap();
118+
let isid = c.add_file(file.to_str().unwrap(), 5, 15, 0x1337).unwrap();
119+
let mut i = img_with_file();
120+
i.add_cached(&mut c, isid, Asid::new(Some(3), Some(4))).unwrap();
121+
assert_eq!(
122+
i.remove_by_asid(Asid::new(Some(3), Some(4))).unwrap(),
123+
1
124+
);
125+
}
49126
}
50127

51128
unsafe extern "C" fn read_callback(buffer: *mut u8,
@@ -115,11 +192,11 @@ impl<'a> Image<'a> {
115192
let cfilename = CString::new(filename).map_err(|_| PtError::new(
116193
PtErrorCode::Invalid,
117194
"Error converting filename to Cstring as it contains null bytes")
118-
)?.as_ptr();
195+
)?;
119196

120197
extract_pterr( unsafe {
121198
pt_image_remove_by_filename(self.inner,
122-
cfilename,
199+
cfilename.as_ptr(),
123200
&asid.0)
124201
})
125202
}
@@ -147,7 +224,7 @@ impl<'a> Image<'a> {
147224
/// Sections that could not be added will be ignored.
148225
/// Returns the number of ignored sections on success.
149226
pub fn copy(&mut self, src: &Image) -> Result<u32, PtError> {
150-
extract_pterr( unsafe { pt_image_copy(self.inner, src.inner)})
227+
extract_pterr( unsafe { pt_image_copy(self.inner, src.inner) })
151228
}
152229

153230
/// Add a section from an image section cache.
@@ -157,10 +234,10 @@ impl<'a> Image<'a> {
157234
/// Returns BadImage if @iscache does not contain @isid.
158235
pub fn add_cached(&mut self,
159236
iscache: &mut SectionCache,
160-
isid: i32,
237+
isid: u32,
161238
asid: Asid) -> Result<(), PtError> {
162239
ensure_ptok( unsafe {
163-
pt_image_add_cached(self.inner, iscache.0, isid, &asid.0
240+
pt_image_add_cached(self.inner, iscache.0, isid as i32, &asid.0
164241
)})
165242
}
166243

@@ -184,11 +261,11 @@ impl<'a> Image<'a> {
184261
let cfilename = CString::new(filename).map_err(|_| PtError::new(
185262
PtErrorCode::Invalid,
186263
"Error converting filename to Cstring as it contains null bytes")
187-
)?.as_ptr();
264+
)?;
188265

189266
ensure_ptok( unsafe {
190267
pt_image_add_file(self.inner,
191-
cfilename,
268+
cfilename.as_ptr(),
192269
offset,
193270
size,
194271
match asid {

src/insn/decoder.rs

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,54 @@ use libipt_sys::{
3636
pt_insn_time
3737
};
3838

39-
pub struct InsnDecoder<T>(pt_insn_decoder, PhantomData<T>);
40-
impl<T> InsnDecoder<T> {
39+
#[cfg(test)]
40+
mod test {
41+
use super::*;
42+
43+
#[test]
44+
fn test_blkdec_alloc() {
45+
InsnDecoder::new(&Config::<()>::new(&mut [0; 0])).unwrap();
46+
}
47+
48+
#[test ]
49+
fn test_blkdec_props() {
50+
// this just checks memory safety for property access
51+
// usage can be found in the integration tests
52+
let mut b = InsnDecoder::new(&Config::<()>::new(&mut [0; 0])).unwrap();
53+
let a = b.asid().unwrap();
54+
assert!(a.cr3().is_none());
55+
assert!(a.vmcs().is_none());
56+
57+
assert!(b.core_bus_ratio().is_err());
58+
assert!(b.event().is_err());
59+
assert!(b.config().is_ok());
60+
assert!(b.image().unwrap().name().is_none());
61+
assert!(b.offset().is_err());
62+
assert!(b.sync_offset().is_err());
63+
assert!(b.next().is_err());
64+
assert!(b.sync_backward().is_err());
65+
assert!(b.sync_forward().is_err());
66+
assert!(b.time().is_err());
67+
}
68+
}
69+
70+
pub struct InsnDecoder<'a, T>(&'a mut pt_insn_decoder, PhantomData<T>);
71+
impl<'a, T> InsnDecoder<'a, T> {
4172
/// Allocate an Intel PT instruction flow decoder.
4273
///
4374
/// The decoder will work on the buffer defined in @config,
4475
/// it shall contain raw trace data and remain valid for the lifetime of the decoder.
4576
/// The decoder needs to be synchronized before it can be used.
4677
pub fn new(cfg: &Config<T>) -> Result<Self, PtError> {
47-
deref_ptresult(unsafe { pt_insn_alloc_decoder(cfg.0.as_ref()) })
48-
.map(|d| InsnDecoder::<T>(*d, PhantomData))
78+
deref_ptresult_mut(unsafe { pt_insn_alloc_decoder(cfg.0.as_ref()) })
79+
.map(|d| InsnDecoder::<T>(d, PhantomData))
4980
}
5081

5182
/// Return the current address space identifier.
5283
pub fn asid(&self) -> Result<Asid, PtError> {
5384
let mut asid: pt_asid = unsafe { mem::zeroed() };
5485
ensure_ptok(unsafe {
55-
pt_insn_asid(&self.0,
86+
pt_insn_asid(self.0,
5687
&mut asid,
5788
mem::size_of::<pt_asid>())
5889
}).map(|_| Asid(asid))
@@ -65,7 +96,7 @@ impl<T> InsnDecoder<T> {
6596
/// Returns NoCbr if there has not been a CBR packet.
6697
pub fn core_bus_ratio(&mut self) -> Result<u32, PtError> {
6798
let mut cbr: u32 = 0;
68-
ensure_ptok(unsafe { pt_insn_core_bus_ratio(&mut self.0, &mut cbr) })
99+
ensure_ptok(unsafe { pt_insn_core_bus_ratio(self.0, &mut cbr) })
69100
.map(|_| cbr)
70101
}
71102

@@ -76,14 +107,14 @@ impl<T> InsnDecoder<T> {
76107
pub fn event(&mut self) -> Result<(Event, Status), PtError> {
77108
let mut evt: pt_event = unsafe { mem::zeroed() };
78109
extract_pterr(unsafe {
79-
pt_insn_event(&mut self.0,
110+
pt_insn_event(self.0,
80111
&mut evt,
81112
mem::size_of::<pt_event>())
82113
}).map(|s| (Event(evt), Status::from_bits(s).unwrap()))
83114
}
84115

85116
pub fn config(&self) -> Result<Config<T>, PtError> {
86-
deref_ptresult(unsafe { pt_insn_get_config(&self.0) })
117+
deref_ptresult(unsafe { pt_insn_get_config(self.0) })
87118
.map(Config::from)
88119
}
89120

@@ -92,7 +123,7 @@ impl<T> InsnDecoder<T> {
92123
/// The returned image may be modified as long as no decoder that uses this image is running.
93124
/// Returns the traced image the decoder uses for reading memory.
94125
pub fn image(&mut self) -> Result<Image, PtError> {
95-
deref_ptresult_mut(unsafe { pt_insn_get_image(&mut self.0) })
126+
deref_ptresult_mut(unsafe { pt_insn_get_image(self.0) })
96127
.map(Image::from)
97128
}
98129

@@ -101,7 +132,7 @@ impl<T> InsnDecoder<T> {
101132
/// Returns Nosync if decoder is out of sync.
102133
pub fn offset(&self) -> Result<u64, PtError> {
103134
let mut off: u64 = 0;
104-
ensure_ptok(unsafe { pt_insn_get_offset(&self.0, &mut off) })
135+
ensure_ptok(unsafe { pt_insn_get_offset(self.0, &mut off) })
105136
.map(|_| off)
106137
}
107138

@@ -110,7 +141,7 @@ impl<T> InsnDecoder<T> {
110141
/// Returns Nosync if @decoder is out of sync.
111142
pub fn sync_offset(&self) -> Result<u64, PtError> {
112143
let mut off = 0;
113-
ensure_ptok(unsafe { pt_insn_get_sync_offset(&self.0, &mut off) })
144+
ensure_ptok(unsafe { pt_insn_get_sync_offset(self.0, &mut off) })
114145
.map(|_| off)
115146
}
116147

@@ -129,7 +160,7 @@ impl<T> InsnDecoder<T> {
129160
pub fn next(&mut self) -> Result<(Insn, Status), PtError> {
130161
let mut insn: pt_insn = unsafe { mem::zeroed() };
131162
extract_pterr(unsafe {
132-
pt_insn_next(&mut self.0,
163+
pt_insn_next(self.0,
133164
&mut insn,
134165
mem::size_of::<pt_insn>())
135166
}).map(|s| (Insn(insn), Status::from_bits(s).unwrap()))
@@ -142,7 +173,7 @@ impl<T> InsnDecoder<T> {
142173
/// Only one image can be active at any time.
143174
pub fn set_image(&mut self, img: Option<&mut Image>) -> Result<(), PtError> {
144175
ensure_ptok(unsafe {
145-
pt_insn_set_image(&mut self.0,
176+
pt_insn_set_image(self.0,
146177
match img {
147178
None => ptr::null_mut(),
148179
Some(i) => i.inner
@@ -151,7 +182,7 @@ impl<T> InsnDecoder<T> {
151182
}
152183

153184
pub fn sync_backward(&mut self) -> Result<(), PtError> {
154-
ensure_ptok(unsafe { pt_insn_sync_backward(&mut self.0) })
185+
ensure_ptok(unsafe { pt_insn_sync_backward(self.0) })
155186
}
156187

157188
/// Synchronize an Intel PT instruction flow decoder.
@@ -165,7 +196,7 @@ impl<T> InsnDecoder<T> {
165196
/// Returns BadPacket if an unknown packet payload is encountered.
166197
/// Returns Eos if no further synchronization point is found.
167198
pub fn sync_forward(&mut self) -> Result<(), PtError> {
168-
ensure_ptok(unsafe { pt_insn_sync_forward(&mut self.0) })
199+
ensure_ptok(unsafe { pt_insn_sync_forward(self.0) })
169200
}
170201

171202
/// Manually synchronize an Intel PT instruction flow decoder.
@@ -178,7 +209,7 @@ impl<T> InsnDecoder<T> {
178209
/// Returns Eos if decoder reaches the end of its trace buffer.
179210
/// Returns Nosync if there is no syncpoint at @offset.
180211
pub fn sync_set(&mut self, offset: u64) -> Result<(), PtError> {
181-
ensure_ptok(unsafe { pt_insn_sync_set(&mut self.0, offset) })
212+
ensure_ptok(unsafe { pt_insn_sync_set(self.0, offset) })
182213
}
183214

184215
/// Return the current time.
@@ -200,7 +231,7 @@ impl<T> InsnDecoder<T> {
200231
let mut lost_cyc: u32 = 0;
201232
ensure_ptok(
202233
unsafe {
203-
pt_insn_time(&mut self.0,
234+
pt_insn_time(self.0,
204235
&mut time,
205236
&mut lost_mtc,
206237
&mut lost_cyc)
@@ -209,6 +240,6 @@ impl<T> InsnDecoder<T> {
209240
}
210241
}
211242

212-
impl<T> Drop for InsnDecoder<T> {
213-
fn drop(&mut self) { unsafe { pt_insn_free_decoder(&mut self.0) } }
243+
impl<'a, T> Drop for InsnDecoder<'a, T> {
244+
fn drop(&mut self) { unsafe { pt_insn_free_decoder(self.0) } }
214245
}

src/insn/insn.rs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,36 @@ use std::convert::TryFrom;
55

66
use libipt_sys::pt_insn;
77

8+
#[cfg(test)]
9+
mod test {
10+
use super::*;
11+
use libipt_sys::pt_insn_class_ptic_call;
12+
use libipt_sys::pt_exec_mode_ptem_32bit;
13+
14+
#[test]
15+
fn test_insn_props() {
16+
let data: [u8; 15] = [17; 15];
17+
let blk = Insn(pt_insn{
18+
ip: 1,
19+
isid: 2,
20+
mode: pt_exec_mode_ptem_32bit,
21+
iclass: pt_insn_class_ptic_call,
22+
raw: data,
23+
size: 8,
24+
_bitfield_1: pt_insn::new_bitfield_1(0, 1),
25+
__bindgen_padding_0: Default::default()
26+
});
27+
28+
assert_eq!(blk.ip(), 1);
29+
assert_eq!(blk.isid(), 2);
30+
assert_eq!(blk.mode(), ExecModeType::Bit32);
31+
assert_eq!(blk.class(), Class::Call);
32+
assert_eq!(blk.raw(), &data[..8]);
33+
assert!(blk.truncated());
34+
assert!(!blk.speculative());
35+
}
36+
}
37+
838
/// A single traced instruction.
939
#[derive(Clone, Copy)]
1040
pub struct Insn(pub(crate) pt_insn);
@@ -14,13 +44,11 @@ impl Insn {
1444

1545
/// The image section identifier for the section containing this instruction.
1646
///
17-
/// None if the section was not added via an image section cache or the memory was read via the read memory callback.
18-
pub fn isid(self) -> Option<i32> {
19-
match self.0.isid { 0 => None, x => Some(x) }
20-
}
47+
/// A value of zero means that the section did not have an identifier.
48+
pub fn isid(self) -> i32 { self.0.isid }
2149

2250
/// The execution mode.
23-
pub fn exec_mode(self) -> ExecModeType {
51+
pub fn mode(self) -> ExecModeType {
2452
ExecModeType::try_from(self.0.mode)
2553
.expect(concat!("unmatched ExecModeType enum value, ",
2654
"this is a bug in either libipt or the bindings"))

0 commit comments

Comments
 (0)