use dbgscope::dbgeng::{DebugEngine, RegisterValue};
fn show(e: &DebugEngine, cmd: &str) {
match e.execute_command(cmd) {
Ok(out) => print!("{out}"),
Err(err) => println!("ERR: {err}"),
}
}
fn rendered(value: &RegisterValue) -> String {
match value {
RegisterValue::Int(v) => format!("{v:#018x}"),
RegisterValue::Float(v) => format!("{v}"),
RegisterValue::Bytes(bytes) => hex::encode(bytes),
RegisterValue::Unavailable => "(unavailable)".to_string(),
}
}
fn main() {
let e = DebugEngine::new();
let target = std::env::args().nth(1);
match &target {
Some(dump) => {
println!("=== opening dump {dump} ===");
if let Err(err) = e.open_dump(dump) {
println!("open_dump ERR: {err}");
return;
}
if let Err(err) = e.wait_for_event(60_000) {
println!("load wait ERR: {err}");
return;
}
}
None => {
println!("=== launching cmd.exe ===");
if let Err(err) = e.launch_process("cmd.exe /c exit 42") {
println!("launch ERR: {err}");
return;
}
}
}
println!("\n=== r (what a host would have had to parse) ===");
show(&e, "r");
println!("\n=== register_values() ===");
match e.register_values() {
Ok(registers) => {
let subs = registers.iter().filter(|r| r.subregister).count();
println!(
"{} registers ({subs} subregisters), {} unavailable",
registers.len(),
registers
.iter()
.filter(|r| r.value == RegisterValue::Unavailable)
.count()
);
for register in registers.iter().filter(|r| !r.subregister).take(24) {
println!(" {:<10} {}", register.name, rendered(®ister.value));
}
for name in ["xmm0", "st0", "efl", "cs"] {
match registers.iter().find(|r| r.name == name) {
Some(register) => {
println!(" {:<10} {}", register.name, rendered(®ister.value))
}
None => println!(" {name:<10} (not present on this target)"),
}
}
}
Err(err) => println!("register_values ERR: {err}"),
}
match e.instruction_pointer() {
Ok(ip) => println!(" instruction_pointer() = {ip:#018x}"),
Err(err) => println!(" instruction_pointer ERR: {err}"),
}
println!("\n=== lm ===");
show(&e, "lm");
println!("\n=== modules() ===");
match e.modules() {
Ok(modules) => {
println!("{} loaded modules", modules.len());
for module in modules.iter().take(12) {
println!(
" {:#018x}-{:#018x} {:<16} {:<24} {:?}{}",
module.base,
module.end(),
module.name,
module.image_name,
module.symbols,
if module.user_mode { " [user]" } else { "" }
);
}
let nameless = modules.iter().filter(|m| m.name.is_empty()).count();
println!("modules with no name: {nameless} (expected 0)");
}
Err(err) => println!("modules ERR: {err}"),
}
println!("\n=== unloaded_modules() ===");
match e.unloaded_modules() {
Ok(modules) => {
println!("{} unloaded modules", modules.len());
for module in modules.iter().take(8) {
println!(
" {:#018x}-{:#018x} {:<16} {:<24} {:?}",
module.base,
module.end(),
module.name,
module.image_name,
module.symbols,
);
}
let nameless = modules.iter().filter(|m| m.image_name.is_empty()).count();
println!("unloaded modules with no image name: {nameless} (expected 0)");
let named = modules.iter().filter(|m| !m.name.is_empty()).count();
println!("unloaded modules with a module name: {named} (expected 0)");
let flagged = modules.iter().filter(|m| m.unloaded).count();
println!(
"flagged unloaded by the engine: {flagged} (expected {})",
modules.len()
);
}
Err(err) => println!("unloaded_modules ERR: {err}"),
}
println!("\n=== breakpoints ===");
let resolvable = match target {
Some(_) => "nt!KeBugCheckEx",
None => "ntdll!NtCreateFile",
};
show(&e, &format!("bp {resolvable}"));
show(&e, "bp nosuchmodule!NoSuchSymbol");
show(&e, "bl");
match e.breakpoints() {
Ok(breakpoints) => {
println!("{} breakpoints", breakpoints.len());
for bp in &breakpoints {
println!(
" #{} {:?} address={} expr={:?} enabled={} deferred={} passes={}/{}",
bp.id,
bp.kind,
bp.address
.map_or_else(|| "(unresolved)".to_string(), |a| format!("{a:#018x}")),
bp.expression,
bp.enabled,
bp.deferred,
bp.passes_remaining,
bp.pass_count,
);
}
}
Err(err) => println!("breakpoints ERR: {err}"),
}
let _ = e.end_session();
}