Skip to content

Commit 67667cb

Browse files
committed
cleanups + tests
1 parent 34799c7 commit 67667cb

File tree

6 files changed

+110
-78
lines changed

6 files changed

+110
-78
lines changed

src/gxa.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use std::ops::AddAssign;
1919
use std::str::FromStr;
2020

2121
use crate::pxe::Pfn;
22-
use crate::structs::Page;
22+
use crate::structs::PageKind;
2323

2424
/// A bunch of useful methods to manipulate 64-bit addresses of
2525
/// any kind.
@@ -47,7 +47,7 @@ pub trait Gxa: Sized + Default + Copy + From<u64> {
4747
Self::from(
4848
self.page_align()
4949
.u64()
50-
.checked_add(Page::size())
50+
.checked_add(PageKind::Normal.size())
5151
.expect("Cannot overflow"),
5252
)
5353
}

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ pub use bits::Bits;
1212
pub use error::{AddrTranslationError, KdmpParserError, PxeNotPresent, Result};
1313
pub use gxa::{Gpa, Gva, Gxa};
1414
pub use map::{MappedFileReader, Reader};
15-
pub use parse::KernelDumpParser;
15+
pub use parse::{KernelDumpParser, TranslationDetails};
1616
pub use pxe::{Pfn, Pxe, PxeFlags};
17-
pub use structs::{Context, DumpType, Header64};
17+
pub use structs::{Context, DumpType, Header64, PageKind};

src/parse.rs

Lines changed: 12 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,40 +16,12 @@ use crate::gxa::Gxa;
1616
use crate::map::{MappedFileReader, Reader};
1717
use crate::structs::{
1818
BmpHeader64, Context, DUMP_HEADER64_EXPECTED_SIGNATURE, DUMP_HEADER64_EXPECTED_VALID_DUMP,
19-
DumpType, ExceptionRecord64, FullRdmpHeader64, Header64, HugePage, KdDebuggerData64,
20-
KernelRdmpHeader64, LargePage, LdrDataTableEntry, ListEntry, Page, PfnRange, PhysmemDesc,
21-
PhysmemMap, PhysmemRun, UnicodeString, read_struct,
19+
DumpType, ExceptionRecord64, FullRdmpHeader64, Header64, KdDebuggerData64, KernelRdmpHeader64,
20+
LdrDataTableEntry, ListEntry, PageKind, PfnRange, PhysmemDesc, PhysmemMap, PhysmemRun,
21+
UnicodeString, read_struct,
2222
};
2323
use crate::{AddrTranslationError, Gpa, Gva, KdmpParserError, Pfn, Pxe};
2424

25-
/// The kind of physical page.
26-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27-
pub enum PageKind {
28-
/// A normal 4kb page.
29-
Normal,
30-
/// A large 2mb page.
31-
Large,
32-
/// A huge 1gb page.
33-
Huge,
34-
}
35-
36-
impl PageKind {
37-
/// Size in bytes of the page.
38-
pub fn size(&self) -> u64 {
39-
match self {
40-
Self::Normal => Page::size(),
41-
Self::Large => LargePage::size(),
42-
Self::Huge => HugePage::size(),
43-
}
44-
}
45-
46-
pub fn page_offset_of(&self, addr: u64) -> u64 {
47-
let mask = self.size() - 1;
48-
49-
addr & mask
50-
}
51-
}
52-
5325
/// The details related to a virtual to physical address translation.
5426
#[derive(Debug)]
5527
pub struct TranslationDetails {
@@ -71,7 +43,7 @@ pub struct TranslationDetails {
7143

7244
impl TranslationDetails {
7345
pub fn new(pfn: Pfn, offset: u64, page_kind: PageKind, pxes: &[Pxe]) -> Self {
74-
let readable = pxes.iter().all(Pxe::readable);
46+
let readable = pxes.iter().all(Pxe::present);
7547
let writable = pxes.iter().all(Pxe::writable);
7648
let executable = pxes.iter().all(Pxe::executable);
7749
let user_accessible = pxes.iter().all(Pxe::user_accessible);
@@ -103,7 +75,7 @@ fn gpa_from_bitmap(bitmap_idx: u64, bit_idx: usize) -> Option<Gpa> {
10375
}
10476

10577
fn gpa_from_pfn_range(pfn_range: &PfnRange, page_idx: u64) -> Option<Gpa> {
106-
let offset = page_idx.checked_mul(Page::size())?;
78+
let offset = page_idx.checked_mul(PageKind::Normal.size())?;
10779

10880
Some(Pfn::new(pfn_range.page_file_number).gpa_with_offset(offset))
10981
}
@@ -574,7 +546,7 @@ impl KernelDumpParser {
574546
// So let's figure out the maximum amount of bytes we can read off this page.
575547
// Either, we read it until its end, or we stop if the user wants us to read
576548
// less.
577-
let left_in_page = (Page::size() - gpa.offset()) as usize;
549+
let left_in_page = (PageKind::Normal.size() - gpa.offset()) as usize;
578550
let amount_wanted = min(amount_left, left_in_page);
579551
// Figure out where we should read into.
580552
let slice = &mut buf[total_read..total_read + amount_wanted];
@@ -653,7 +625,7 @@ impl KernelDumpParser {
653625
let pd_base = pdpte.pfn.gpa();
654626
if pdpte.large_page() {
655627
let page_kind = PageKind::Huge;
656-
let offset = page_kind.page_offset_of(gva.u64());
628+
let offset = page_kind.page_offset(gva.u64());
657629
return Ok(TranslationDetails::new(pdpte.pfn, offset, page_kind, &[
658630
pml4e, pdpte,
659631
]));
@@ -671,7 +643,7 @@ impl KernelDumpParser {
671643
let pt_base = pde.pfn.gpa();
672644
if pde.large_page() {
673645
let page_kind = PageKind::Large;
674-
let offset = page_kind.page_offset_of(gva.u64());
646+
let offset = page_kind.page_offset(gva.u64());
675647
return Ok(TranslationDetails::new(
676648
pde.pfn,
677649
offset,
@@ -691,7 +663,7 @@ impl KernelDumpParser {
691663
}
692664

693665
let page_kind = PageKind::Normal;
694-
let offset = page_kind.page_offset_of(gva.u64());
666+
let offset = page_kind.page_offset(gva.u64());
695667

696668
Ok(TranslationDetails::new(pte.pfn, offset, page_kind, &[
697669
pml4e, pdpte, pde, pte,
@@ -936,7 +908,7 @@ impl KernelDumpParser {
936908

937909
// Move the page offset along.
938910
page_offset = page_offset
939-
.checked_add(Page::size())
911+
.checked_add(PageKind::Normal.size())
940912
.ok_or(KdmpParserError::PageOffsetOverflow(run_idx, page_idx))?;
941913
}
942914
}
@@ -984,7 +956,7 @@ impl KernelDumpParser {
984956

985957
let insert = physmem.insert(pa, page_offset);
986958
debug_assert!(insert.is_none());
987-
page_offset = page_offset.checked_add(Page::size()).ok_or(
959+
page_offset = page_offset.checked_add(PageKind::Normal.size()).ok_or(
988960
KdmpParserError::BitmapPageOffsetOverflow(bitmap_idx, bit_idx),
989961
)?;
990962
}
@@ -1072,7 +1044,7 @@ impl KernelDumpParser {
10721044
let insert = physmem.insert(gpa, page_offset);
10731045
debug_assert!(insert.is_none());
10741046
page_offset = page_offset
1075-
.checked_add(Page::size())
1047+
.checked_add(PageKind::Normal.size())
10761048
.ok_or(KdmpParserError::Overflow("w/ page_offset"))?;
10771049
}
10781050

src/pxe.rs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ impl Pxe {
120120
/// Pfn::new(0x6d600),
121121
/// PxeFlags::Present
122122
/// );
123-
/// assert_eq!(p.present(), true);
123+
/// assert!(p.present());
124124
/// let np = Pxe::new(
125125
/// Pfn::new(0x1337),
126126
/// PxeFlags::UserAccessible
127127
/// );
128-
/// assert_eq!(np.present(), false);
128+
/// assert!(!np.present());
129129
/// # }
130130
/// ```
131131
pub fn present(&self) -> bool {
@@ -143,12 +143,12 @@ impl Pxe {
143143
/// Pfn::new(0x6d600),
144144
/// PxeFlags::LargePage
145145
/// );
146-
/// assert_eq!(p.large_page(), true);
146+
/// assert!(p.large_page());
147147
/// let np = Pxe::new(
148148
/// Pfn::new(0x1337),
149149
/// PxeFlags::UserAccessible
150150
/// );
151-
/// assert_eq!(np.large_page(), false);
151+
/// assert!(!np.large_page());
152152
/// # }
153153
/// ```
154154
pub fn large_page(&self) -> bool {
@@ -164,26 +164,61 @@ impl Pxe {
164164
/// # fn main() {
165165
/// let p = Pxe::from(0x166B7880);
166166
/// let np = Pxe::from(0xA000000077AF867);
167-
/// assert_eq!(p.transition(), true);
168-
/// assert_eq!(np.transition(), false);
167+
/// assert!(p.transition());
168+
/// assert!(!np.transition());
169169
/// # }
170170
/// ```
171171
pub fn transition(&self) -> bool {
172172
!self.present() && self.flags.contains(PxeFlags::Transition)
173173
}
174174

175-
pub fn readable(&self) -> bool {
176-
self.present()
177-
}
178-
175+
/// Is the memory described by this [`Pxe`] writable?
176+
///
177+
/// # Examples
178+
///
179+
/// ```
180+
/// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
181+
/// # fn main() {
182+
/// let w = Pxe::from(0x2709063);
183+
/// let ro = Pxe::from(0x8A00000002C001A1);
184+
/// assert!(w.writable());
185+
/// assert!(!ro.writable());
186+
/// # }
187+
/// ```
179188
pub fn writable(&self) -> bool {
180189
self.flags.contains(PxeFlags::Writable)
181190
}
182191

192+
/// Is the memory described by this [`Pxe`] executable?
193+
///
194+
/// # Examples
195+
///
196+
/// ```
197+
/// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
198+
/// # fn main() {
199+
/// let x = Pxe::from(0x270a063);
200+
/// let nx = Pxe::from(0x8A00000002C001A1);
201+
/// assert!(x.executable());
202+
/// assert!(!nx.executable());
203+
/// # }
204+
/// ```
183205
pub fn executable(&self) -> bool {
184206
!self.flags.contains(PxeFlags::NoExecute)
185207
}
186208

209+
/// Is the memory described by this [`Pxe`] accessible by user-mode?
210+
///
211+
/// # Examples
212+
///
213+
/// ```
214+
/// # use kdmp_parser::{Pxe, PxeFlags, Pfn};
215+
/// # fn main() {
216+
/// let u = Pxe::from(0x8000000F34E5025);
217+
/// let s = Pxe::from(0x270A063);
218+
/// assert!(u.user_accessible());
219+
/// assert!(!s.user_accessible());
220+
/// # }
221+
/// ```
187222
pub fn user_accessible(&self) -> bool {
188223
self.flags.contains(PxeFlags::UserAccessible)
189224
}

src/structs.rs

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,32 @@ use std::{io, mem, slice};
77
use crate::error::Result;
88
use crate::{Gpa, KdmpParserError, Reader};
99

10-
/// A page.
11-
pub struct Page;
12-
13-
impl Page {
14-
/// Get the size of a memory page.
15-
pub const fn size() -> u64 {
16-
0x1_000
17-
}
10+
/// The different kind of physical pages.
11+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12+
pub enum PageKind {
13+
/// A normal 4kb page.
14+
Normal,
15+
/// A large 2mb page.
16+
Large,
17+
/// A huge 1gb page.
18+
Huge,
1819
}
1920

20-
/// A large page.
21-
pub struct LargePage;
22-
23-
impl LargePage {
24-
/// Get the size of a large memory page.
25-
pub const fn size() -> u64 {
26-
2 * 1_024 * 1_024
21+
impl PageKind {
22+
/// Size in bytes of the page.
23+
pub fn size(&self) -> u64 {
24+
match self {
25+
Self::Normal => 4 * 1_024,
26+
Self::Large => 2 * 1_024 * 1_024,
27+
Self::Huge => 1_024 * 1_024 * 1_024,
28+
}
2729
}
28-
}
2930

30-
pub struct HugePage;
31+
/// Extract the page offset of `addr`.
32+
pub fn page_offset(&self, addr: u64) -> u64 {
33+
let mask = self.size() - 1;
3134

32-
impl HugePage {
33-
/// Get the size of a huge memory page.
34-
pub const fn size() -> u64 {
35-
1_024 * 1_024 * 1_024
35+
addr & mask
3636
}
3737
}
3838

@@ -213,13 +213,13 @@ pub struct PhysmemRun {
213213
impl PhysmemRun {
214214
/// Calculate a physical address from a run and an index.
215215
///
216-
/// The formulae is: (`base_page` + `page_idx`) * `Page::size()`.
216+
/// The formulae is: (`base_page` + `page_idx`) * `PageKind::Normal.size()`.
217217
pub fn phys_addr(&self, page_idx: u64) -> Option<Gpa> {
218218
debug_assert!(page_idx < self.page_count);
219219

220220
self.base_page
221221
.checked_add(page_idx)?
222-
.checked_mul(Page::size())
222+
.checked_mul(PageKind::Normal.size())
223223
.map(Gpa::new)
224224
}
225225
}

tests/regression.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::fs::File;
55
use std::ops::Range;
66
use std::path::PathBuf;
77

8-
use kdmp_parser::{AddrTranslationError, Gpa, Gva, KdmpParserError, KernelDumpParser};
8+
use kdmp_parser::{AddrTranslationError, Gpa, Gva, KdmpParserError, KernelDumpParser, PageKind};
99
use serde::Deserialize;
1010

1111
/// Convert an hexadecimal encoded integer string into a `u64`.
@@ -544,4 +544,29 @@ fn regressions() {
544544
0x00, 0x74, 0x00, 0x69, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x42, 0x00, 0x72, 0x00, 0x6f, 0x00,
545545
0x6b, 0x00, 0x65, 0x00
546546
]);
547+
548+
// Read from the middle of a large page.
549+
// ```text
550+
// 32.1: kd> !pte nt
551+
// VA fffff80122800000
552+
// PXE at FFFFF5FAFD7EBF80 PPE at FFFFF5FAFD7F0020 PDE at FFFFF5FAFE0048A0 PTE at FFFFF5FC00914000
553+
// contains 0000000002709063 contains 000000000270A063 contains 8A000000048001A1 contains 0000000000000000
554+
// pfn 2709 ---DA--KWEV pfn 270a ---DA--KWEV pfn 4800 -GL-A--KR-V LARGE PAGE pfn 4800
555+
// ```
556+
let parser = KernelDumpParser::new(&wow64.file).unwrap();
557+
let tr = parser
558+
.virt_translate_with_dtb(0xfffff80122800000.into(), 0x5dc6f000.into())
559+
.unwrap();
560+
assert!(matches!(tr.page_kind, PageKind::Large));
561+
assert!(matches!(tr.pfn.u64(), 0x4800));
562+
let mut buffer = [0; 0x10];
563+
assert!(
564+
parser
565+
.virt_read_exact(Gva::new(0xfffff80122800000 + 0x100000), &mut buffer)
566+
.is_ok()
567+
);
568+
assert_eq!(buffer, [
569+
0x54, 0x3a, 0x65, 0x00, 0xbc, 0x82, 0x0c, 0x00, 0x5c, 0x3a, 0x65, 0x00, 0x86, 0x3b, 0x65,
570+
0x00
571+
]);
547572
}

0 commit comments

Comments
 (0)