use crate::backend::MemoryOps;
use crate::error::{Error, Result};
use crate::guest::WinObject;
use crate::target::Target;
use crate::types::VirtAddr;
pub const MAX_PROCESSORS: u16 = 2048;
fn kernel(target: &Target) -> Result<&WinObject> {
Ok(&target.guest()?.ntoskrnl)
}
fn processor_block(target: &Target, index: u16) -> Result<VirtAddr> {
if index >= MAX_PROCESSORS {
return Err(Error::DebugInfo(format!(
"processor index {index} exceeds the supported bound of {MAX_PROCESSORS}"
)));
}
let nt = kernel(target)?;
let symbol = nt.symbol("KiProcessorBlock")?;
nt.memory().read(symbol.address() + (u64::from(index) * 8))
}
fn prcb_offset(target: &Target) -> Result<u64> {
kernel(target)?
.types()
.layout("_KPCR")?
.field_offset("Prcb")
}
fn validate_pointer(kind: &str, index: u16, value: VirtAddr) -> Result<VirtAddr> {
if value.is_zero() {
return Err(Error::DebugInfo(format!(
"KiProcessorBlock[{index}] contains a null {kind}"
)));
}
Ok(value)
}
pub fn kpcr_for_processor(target: &Target, index: u16) -> Result<VirtAddr> {
let entry = validate_pointer("processor pointer", index, processor_block(target, index)?)?;
let offset = prcb_offset(target)?;
let address = entry.0.checked_sub(offset).ok_or_else(|| {
Error::DebugInfo(format!(
"KiProcessorBlock[{index}] KPRCB underflows _KPCR.Prcb"
))
})?;
Ok(VirtAddr(address))
}
pub fn kprcb_for_processor(target: &Target, index: u16) -> Result<VirtAddr> {
validate_pointer("processor pointer", index, processor_block(target, index)?)
}
pub fn processor_count(target: &Target) -> Result<u16> {
let nt = kernel(target)?;
if let Ok(number_processors) = nt.symbol("KeNumberProcessors") {
if let Ok(value) = number_processors.read::<u8>()
&& value != 0
{
return Ok(u16::from(value));
}
}
let block = nt.symbol("KiProcessorBlock")?.address();
let memory = nt.memory();
let mut count = 0u16;
for index in 0..MAX_PROCESSORS {
match memory.read::<VirtAddr>(block + (u64::from(index) * 8)) {
Ok(entry) if !entry.is_zero() => count += 1,
Ok(_) | Err(_) => break,
}
}
if count != 0 {
Ok(count)
} else {
Err(Error::DebugInfo(
"processor count unavailable (KeNumberProcessors and KiProcessorBlock unreadable)"
.into(),
))
}
}