From 0daf7c677cd2821a7aa1fdeb79b9ace835b651f1 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 18 Oct 2024 18:29:14 +0300 Subject: [PATCH] i686: add single-step debugging --- kernel/arch/i686/src/context.S | 3 +- kernel/arch/i686/src/context.rs | 16 ++- kernel/libk/src/task/binary/elf.rs | 10 +- kernel/libk/src/task/process.rs | 10 +- kernel/libk/src/task/thread.rs | 7 +- kernel/src/arch/i686/exception.rs | 18 ++- kernel/src/arch/i686/peripherals/textfb.rs | 2 +- lib/abi/src/debug.rs | 1 + lib/libyalloc/src/allocator.rs | 10 +- userspace/Cargo.lock | 106 ++++++++++++++++++ userspace/Cargo.toml | 2 +- userspace/rdb/Cargo.toml | 5 +- userspace/rdb/src/aarch64.rs | 5 +- userspace/rdb/src/debugger.rs | 10 +- userspace/rdb/src/main.rs | 12 +- userspace/rdb/src/state.rs | 6 +- userspace/rdb/src/x86.rs | 123 +++++++++++++++++++++ userspace/rdb/src/x86_64.rs | 93 ---------------- xtask/src/build/userspace.rs | 2 +- 19 files changed, 308 insertions(+), 133 deletions(-) create mode 100644 userspace/rdb/src/x86.rs delete mode 100644 userspace/rdb/src/x86_64.rs diff --git a/kernel/arch/i686/src/context.S b/kernel/arch/i686/src/context.S index 8af4a888..2d4dfa6f 100644 --- a/kernel/arch/i686/src/context.S +++ b/kernel/arch/i686/src/context.S @@ -108,12 +108,13 @@ __i686_switch_and_drop: // %esp + 0: return // %esp + 4: destination // %esp + 8: thread to drop - + mov 8(%esp), %ecx mov 4(%esp), %eax // Switch to stack mov (%eax), %esp LOAD_TASK_STATE + // TODO actually drop the thread ret diff --git a/kernel/arch/i686/src/context.rs b/kernel/arch/i686/src/context.rs index adb658dc..78905562 100644 --- a/kernel/arch/i686/src/context.rs +++ b/kernel/arch/i686/src/context.rs @@ -328,8 +328,12 @@ impl TaskFrame for InterruptFrame { self.eax = value as u32; } - fn set_single_step(&mut self, _step: bool) { - todo!() + fn set_single_step(&mut self, step: bool) { + if step { + self.eflags |= 1 << 8; + } else { + self.eflags &= !(1 << 8); + } } fn set_return_value(&mut self, value: u64) { @@ -392,8 +396,12 @@ impl TaskFrame for ExceptionFrame { self.eax = value as u32; } - fn set_single_step(&mut self, _step: bool) { - todo!() + fn set_single_step(&mut self, step: bool) { + if step { + self.eflags |= 1 << 8; + } else { + self.eflags &= !(1 << 8); + } } fn set_return_value(&mut self, value: u64) { diff --git a/kernel/libk/src/task/binary/elf.rs b/kernel/libk/src/task/binary/elf.rs index 7801efd1..714c36e5 100644 --- a/kernel/libk/src/task/binary/elf.rs +++ b/kernel/libk/src/task/binary/elf.rs @@ -179,7 +179,7 @@ pub fn load_elf_from_file( // Find out image size let (vaddr_min, vaddr_max) = elf_virtual_range(&elf); - let image_load_base = elf_load_address(elf.ehdr.e_type, vaddr_min); + let (image_load_base, ip_offset) = elf_load_address(elf.ehdr.e_type, vaddr_min); let image_load_size = vaddr_max - vaddr_min; log::debug!( @@ -213,6 +213,7 @@ pub fn load_elf_from_file( Ok(ProcessImage { entry, + ip_offset, tls, load_base: image_load_base, }) @@ -299,13 +300,14 @@ pub fn elf_virtual_range( (vaddr_min, vaddr_max) } -fn elf_load_address(elf_type: u16, virtual_address: usize) -> usize { +fn elf_load_address(elf_type: u16, virtual_address: usize) -> (usize, usize) { match elf_type { - elf::abi::ET_EXEC => virtual_address, + elf::abi::ET_EXEC => (virtual_address, 0), // TODO ASLR through random? elf::abi::ET_DYN => { let index = random::range(0x5000, 0x20000); - (index as usize) * 0x1000 + let base = (index as usize) * 0x1000; + (base, base) } // Handled in load_elf_from_file() _ => unreachable!(), diff --git a/kernel/libk/src/task/process.rs b/kernel/libk/src/task/process.rs index 4fb5f011..4d066906 100644 --- a/kernel/libk/src/task/process.rs +++ b/kernel/libk/src/task/process.rs @@ -51,6 +51,7 @@ pub struct ProcessManager { #[derive(Clone)] pub struct ProcessImage { pub load_base: usize, + pub ip_offset: usize, /// Entry point address pub entry: usize, /// Thread-local storage information @@ -234,8 +235,12 @@ impl Process { self.inner.read().space.clone().unwrap() } + pub fn map_image T>(&self, f: F) -> Option { + self.inner.read().image.as_ref().map(f) + } + pub fn image_base(&self) -> Option { - self.inner.read().image.as_ref().map(|img| img.load_base) + self.map_image(|image| image.load_base) } pub fn as_single_thread(&self) -> Option> { @@ -329,9 +334,10 @@ impl Process { let inner = proc.inner.read(); if !proc.has_exited() && inner.group_id == group_id { log::debug!( - "Deliver group ({}) signal to {}: {:?}", + "Deliver group ({}) signal to {} ({:?}): {:?}", group_id, proc.id, + proc.name, signal ); drop(inner); diff --git a/kernel/libk/src/task/thread.rs b/kernel/libk/src/task/thread.rs index bf8735f5..daba8b22 100644 --- a/kernel/libk/src/task/thread.rs +++ b/kernel/libk/src/task/thread.rs @@ -456,6 +456,7 @@ impl CurrentThread { // Single step cleared if !debug.single_step { + log::debug!("Clear single step ({} {:?})", self.id, self.name); frame.set_single_step(false); return; } @@ -494,9 +495,13 @@ impl CurrentThread { // Send initial frame let saved_frame = frame.store(); + let (image_base, ip_offset) = process + .map_image(|img| (img.load_base, img.ip_offset)) + .unwrap(); debugger .send(&DebugFrame::Startup { - image_base: process.image_base().unwrap(), + image_base, + ip_offset, frame: saved_frame, }) .ok(); diff --git a/kernel/src/arch/i686/exception.rs b/kernel/src/arch/i686/exception.rs index 2b88ee54..f1617c24 100644 --- a/kernel/src/arch/i686/exception.rs +++ b/kernel/src/arch/i686/exception.rs @@ -162,13 +162,16 @@ fn kernel_exception_inner(kind: ExceptionKind, frame: &ExceptionFrame) -> ! { panic!("Irrecoverable exception") } -fn user_exception_inner(kind: ExceptionKind, frame: &ExceptionFrame) { +fn user_exception_inner(kind: ExceptionKind, frame: &mut ExceptionFrame) { let thread = Thread::current(); - let cr3 = CR3.get(); - warnln!("{:?} in {} {:?}", kind, thread.id, thread.name); - warnln!("CS:EIP = {:#02x}:{:#010x}", frame.cs, frame.eip); - warnln!("CR3 = {:#x}", cr3); + if kind != ExceptionKind::Debug { + let cr3 = CR3.get(); + + warnln!("{:?} in {} {:?}", kind, thread.id, thread.name); + warnln!("CS:EIP = {:#02x}:{:#010x}", frame.cs, frame.eip); + warnln!("CR3 = {:#x}", cr3); + } match kind { ExceptionKind::PageFault => { @@ -183,6 +186,11 @@ fn user_exception_inner(kind: ExceptionKind, frame: &ExceptionFrame) { ExceptionKind::InvalidOpcode => { thread.raise_signal(Signal::Aborted); } + ExceptionKind::Debug => { + // TODO check if the thread was really in single-step mode or has debugging related to + // the address in exception description + thread.handle_single_step(frame); + } _ => { todo!() } diff --git a/kernel/src/arch/i686/peripherals/textfb.rs b/kernel/src/arch/i686/peripherals/textfb.rs index a8ac9a74..e8893857 100644 --- a/kernel/src/arch/i686/peripherals/textfb.rs +++ b/kernel/src/arch/i686/peripherals/textfb.rs @@ -121,7 +121,7 @@ impl DisplayConsole for TextFramebuffer { } fn text_dimensions(&self) -> (usize, usize) { - (self.width, self.height) + (self.height, self.width) } } diff --git a/lib/abi/src/debug.rs b/lib/abi/src/debug.rs index 3addcf08..87ae9cd8 100644 --- a/lib/abi/src/debug.rs +++ b/lib/abi/src/debug.rs @@ -24,6 +24,7 @@ pub enum DebugOperation<'a> { pub enum DebugFrame { Startup { image_base: usize, + ip_offset: usize, frame: SavedFrame, }, Step { diff --git a/lib/libyalloc/src/allocator.rs b/lib/libyalloc/src/allocator.rs index befa7428..d65ff143 100644 --- a/lib/libyalloc/src/allocator.rs +++ b/lib/libyalloc/src/allocator.rs @@ -94,10 +94,12 @@ where current += 1; node = bucket.next; } - panic!( - "BucketList index out of range: contains {} buckets, tried to index {}", - current, index - ); + + loop {} + // panic!( + // "BucketList index out of range: contains {} buckets, tried to index {}", + // current, index + // ); } } diff --git a/userspace/Cargo.lock b/userspace/Cargo.lock index a59ae272..86fb14d1 100644 --- a/userspace/Cargo.lock +++ b/userspace/Cargo.lock @@ -16,12 +16,55 @@ dependencies = [ name = "abi-lib" version = "0.1.0" +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + [[package]] name = "anstyle" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -109,8 +152,10 @@ version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ + "anstream", "anstyle", "clap_lex", + "strsim", ] [[package]] @@ -131,6 +176,12 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + [[package]] name = "colors" version = "0.1.0" @@ -178,6 +229,12 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "elf" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" + [[package]] name = "equivalent" version = "1.0.1" @@ -282,6 +339,15 @@ dependencies = [ "libm", ] +[[package]] +name = "iced-x86" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c447cff8c7f384a7d4f741cfcff32f75f3ad02b406432e8d6c878d56b1edf6b" +dependencies = [ + "lazy_static", +] + [[package]] name = "idna" version = "0.5.0" @@ -311,6 +377,12 @@ dependencies = [ "yggdrasil-rt", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "1.0.10" @@ -602,6 +674,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "rangemap" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" + [[package]] name = "raqote" version = "0.8.3" @@ -614,6 +692,22 @@ dependencies = [ "typed-arena", ] +[[package]] +name = "rdb" +version = "0.1.0" +dependencies = [ + "clap", + "elf", + "iced-x86", + "libterm", + "rangemap", + "serde", + "serde_json", + "thiserror", + "yggdrasil-abi", + "yggdrasil-rt", +] + [[package]] name = "red" version = "0.1.0" @@ -749,6 +843,12 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "sw-composite" version = "0.7.16" @@ -957,6 +1057,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "version_check" version = "0.9.4" diff --git a/userspace/Cargo.toml b/userspace/Cargo.toml index d3dbf8f2..8cf616ea 100644 --- a/userspace/Cargo.toml +++ b/userspace/Cargo.toml @@ -13,6 +13,6 @@ members = [ "netutils", "netutils", # "dyn-loader", -# "rdb" + "rdb" ] exclude = ["dynload-program", "test-kernel-module"] diff --git a/userspace/rdb/Cargo.toml b/userspace/rdb/Cargo.toml index 79aa15b2..77f99e2d 100644 --- a/userspace/rdb/Cargo.toml +++ b/userspace/rdb/Cargo.toml @@ -15,5 +15,8 @@ thiserror = "1.0.58" elf = "0.7.4" rangemap = "1.5.1" -[target.'cfg(target_arch = "x86_64")'.dependencies] +[target.'cfg(any(target_arch = "x86_64", target_arch = "x86"))'.dependencies] +iced-x86 = { version = "1.21.0", default-features = false, features = ["gas", "decoder", "std"] } + +[dev-dependencies] iced-x86 = { version = "1.21.0", default-features = false, features = ["gas", "decoder", "std"] } diff --git a/userspace/rdb/src/aarch64.rs b/userspace/rdb/src/aarch64.rs index 85d56632..2eadbe0c 100644 --- a/userspace/rdb/src/aarch64.rs +++ b/userspace/rdb/src/aarch64.rs @@ -29,6 +29,7 @@ impl InstructionFormatter<()> for Unsupported { impl Target for TargetImpl { type Instruction = (); type InstructionFormatter = Unsupported; + type Register = usize; fn disassemble( _window: &[u8], @@ -44,11 +45,11 @@ impl Target for TargetImpl { fn flags_register_as_display(frame: &SavedFrame) -> impl Display { FlagFormat(frame.spsr_el1) } - fn register_list(frame: &SavedFrame, out: &mut Vec<(String, u64)>) { + fn register_list(frame: &SavedFrame, out: &mut Vec<(String, Self::Register)>) { for i in 0..30 { out.push((format!("x{}", i), frame.gp_regs[i])); } - out.push(("pc".into(), frame.elr_el1)); + out.push(("pc".into(), frame.elr_el1 as _)); out.push(("lr".into(), frame.gp_regs[30])); } fn real_ip(frame: &SavedFrame) -> usize { diff --git a/userspace/rdb/src/debugger.rs b/userspace/rdb/src/debugger.rs index 95ca42e5..5c281cfe 100644 --- a/userspace/rdb/src/debugger.rs +++ b/userspace/rdb/src/debugger.rs @@ -43,8 +43,8 @@ impl Debugger { let segment_headers = extract_segments(image)?; let file = BufReader::new(File::open(image)?); - let term = Term::open().unwrap(); let comm = Comm::open("rdb-1")?; + let term = Term::open().unwrap(); let mut poll = PollChannel::new()?; let comm_fd = comm.as_raw_fd(); @@ -80,9 +80,9 @@ impl Debugger { fn handle_frame(&mut self, frame: DebugFrame) -> Result<(), Error> { match frame { - DebugFrame::Startup { image_base, frame } => { + DebugFrame::Startup { image_base, frame, ip_offset } => { let pid = unsafe { ProcessId::from_raw(self.child.id()) }; - let mut state = State::new(image_base, pid); + let mut state = State::new(image_base, ip_offset, pid); state.update(&frame, true)?; self.state = Some(state); Ok(()) @@ -151,7 +151,7 @@ impl Debugger { T::disassemble( &segment[offset_within_segment..offset_within_segment + amount * 8], - state.current_ip + state.image_base, + state.current_ip + state.ip_offset, amount, ) } @@ -163,7 +163,7 @@ impl Debugger { return Ok(0); }; - let columns = (width - 2) / REG_WIDTH; + let columns = (width + REG_WIDTH - 3) / REG_WIDTH; let mut gpregs = vec![]; T::register_list(&state.last_frame, &mut gpregs); let rows = 1 + (gpregs.len() + columns - 1) / columns; diff --git a/userspace/rdb/src/main.rs b/userspace/rdb/src/main.rs index 51a3eaa8..abb98d97 100644 --- a/userspace/rdb/src/main.rs +++ b/userspace/rdb/src/main.rs @@ -1,16 +1,15 @@ #![feature(yggdrasil_os, if_let_guard)] -use std::{fmt::Display, io, path::PathBuf, process::Command}; +use std::{fmt::{LowerHex, Display}, io, path::PathBuf, process::Command}; use clap::Parser; use debugger::Debugger; use imp::TargetImpl; use yggdrasil_abi::arch::SavedFrame; -#[cfg(target_arch = "x86_64")] -#[path = "x86_64.rs"] +#[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))] +#[path = "x86.rs"] pub mod imp; - -#[cfg(target_arch = "aarch64")] +#[cfg(any(target_arch = "aarch64", rust_analyzer))] #[path = "aarch64.rs"] pub mod imp; @@ -32,6 +31,7 @@ pub enum Error { pub trait Target { type Instruction; type InstructionFormatter: InstructionFormatter; + type Register: LowerHex; fn disassemble( window: &[u8], @@ -40,7 +40,7 @@ pub trait Target { ) -> Result, Error>; fn new_instruction_formatter() -> Self::InstructionFormatter; - fn register_list(frame: &SavedFrame, out: &mut Vec<(String, u64)>); + fn register_list(frame: &SavedFrame, out: &mut Vec<(String, Self::Register)>); fn flags_register_as_display(frame: &SavedFrame) -> impl Display; fn real_ip(frame: &SavedFrame) -> usize; } diff --git a/userspace/rdb/src/state.rs b/userspace/rdb/src/state.rs index 91142549..94a5df90 100644 --- a/userspace/rdb/src/state.rs +++ b/userspace/rdb/src/state.rs @@ -12,18 +12,20 @@ pub struct State { pub last_frame: SavedFrame, pub image_base: usize, + pub ip_offset: usize, _pd: PhantomData, } impl State { - pub fn new(image_base: usize, pid: ProcessId) -> Self { + pub fn new(image_base: usize, ip_offset: usize, pid: ProcessId) -> Self { Self { current_ip: 0, last_frame: SavedFrame::default(), pid, image_base, + ip_offset, _pd: PhantomData, } @@ -37,7 +39,7 @@ impl State { } pub fn update(&mut self, frame: &SavedFrame, _refresh: bool) -> Result<(), Error> { - let ip = T::real_ip(frame) - self.image_base; + let ip = T::real_ip(frame) - self.ip_offset; self.last_frame = frame.clone(); self.current_ip = ip; diff --git a/userspace/rdb/src/x86.rs b/userspace/rdb/src/x86.rs new file mode 100644 index 00000000..2bb9646e --- /dev/null +++ b/userspace/rdb/src/x86.rs @@ -0,0 +1,123 @@ +use std::fmt::{self, Display}; + +use iced_x86::{Decoder, DecoderOptions, Formatter, GasFormatter, Instruction}; +use yggdrasil_abi::arch::SavedFrame; + +use crate::{InstructionFormatter, Target}; + +#[cfg(any(target_pointer_width = "32", rust_analyzer))] +const BITNESS: u32 = 32; +#[cfg(any(target_pointer_width = "64", rust_analyzer))] +const BITNESS: u32 = 64; + +pub struct FlagsDisplay(usize); + +pub struct TargetImpl; + +pub struct NoopFormatter; + +impl fmt::Display for FlagsDisplay { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + const FLAGS: &[(usize, &str)] = &[ + (0, "CF"), + (2, "PF"), + (4, "AF"), + (5, "ZF"), + (6, "SF"), + (9, "IF"), + (10, "DF"), + (11, "OF"), + ]; + write!(f, " {: <#8x} [ ", self.0)?; + for (bit, flag) in FLAGS { + if self.0 & (1 << bit) != 0 { + write!(f, "{} ", flag)?; + } + } + write!(f, "]") + } +} + +impl InstructionFormatter for GasFormatter { + fn format_instruction(&mut self, insn: &Instruction, out: &mut String) { + self.format(insn, out) + } +} + +impl Target for TargetImpl { + type Instruction = Instruction; + type InstructionFormatter = GasFormatter; + type Register = usize; + + fn disassemble( + window: &[u8], + ip: usize, + limit: usize, + ) -> Result, crate::Error> { + let mut instructions = vec![]; + let mut decoder = Decoder::with_ip(BITNESS, window, ip as _, DecoderOptions::NONE); + + while decoder.can_decode() && instructions.len() < limit { + let insn = decoder.decode(); + instructions.push((insn.ip() as usize, insn)); + } + + debug_trace!("{}", instructions.len()); + Ok(instructions) + } + + fn new_instruction_formatter() -> Self::InstructionFormatter { + let mut formatter = GasFormatter::new(); + formatter.options_mut().set_uppercase_hex(false); + formatter.options_mut().set_branch_leading_zeros(false); + formatter + } + + fn register_list(frame: &SavedFrame, out: &mut Vec<(String, Self::Register)>) { + #[cfg(any(target_arch = "x86", rust_analyzer))] + { + out.push(("eax".into(), frame.eax as _)); + out.push(("ecx".into(), frame.ecx as _)); + out.push(("edx".into(), frame.edx as _)); + out.push(("ebx".into(), frame.ebx as _)); + out.push(("esp".into(), frame.user_sp as _)); + out.push(("ebp".into(), frame.ebp as _)); + out.push(("esi".into(), frame.esi as _)); + out.push(("edi".into(), frame.edi as _)); + } + #[cfg(any(target_arch = "x86_64", rust_analyzer))] + { + out.push(("rax".into(), frame.rax as _)); + out.push(("rcx".into(), frame.rcx as _)); + out.push(("rdx".into(), frame.rdx as _)); + out.push(("rbx".into(), frame.rbx as _)); + out.push(("rdi".into(), frame.rdi as _)); + out.push(("rsi".into(), frame.rsi as _)); + out.push(("rsp".into(), frame.user_sp as _)); + out.push(("rbp".into(), frame.rbp as _)); + out.push(("r8".into(), frame.r8 as _)); + out.push(("r9".into(), frame.r9 as _)); + out.push(("r10".into(), frame.r10 as _)); + out.push(("r11".into(), frame.r11 as _)); + out.push(("r12".into(), frame.r12 as _)); + out.push(("r13".into(), frame.r13 as _)); + out.push(("r14".into(), frame.r14 as _)); + out.push(("r15".into(), frame.r15 as _)); + } + } + + fn flags_register_as_display(frame: &SavedFrame) -> impl Display { + #[cfg(any(target_arch = "x86_64", rust_analyzer))] + { + FlagsDisplay(frame.rflags as _) + } + #[cfg(any(target_arch = "x86", rust_analyzer))] + { + FlagsDisplay(frame.eflags as _) + } + } + + fn real_ip(frame: &SavedFrame) -> usize { + frame.user_ip as _ + } +} diff --git a/userspace/rdb/src/x86_64.rs b/userspace/rdb/src/x86_64.rs deleted file mode 100644 index 533dca2c..00000000 --- a/userspace/rdb/src/x86_64.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::fmt::{self, Display}; - -use iced_x86::{Decoder, DecoderOptions, Formatter, GasFormatter, Instruction}; -use yggdrasil_abi::arch::SavedFrame; - -use crate::{InstructionFormatter, Target}; - -pub struct RflagsDisplay(u64); - -pub struct TargetImpl; - -impl fmt::Display for RflagsDisplay { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - const FLAGS: &[(u64, &str)] = &[ - (0, "CF"), - (2, "PF"), - (4, "AF"), - (5, "ZF"), - (6, "SF"), - (9, "IF"), - (10, "DF"), - (11, "OF"), - ]; - write!(f, " {: <#8x} [ ", self.0)?; - for (bit, flag) in FLAGS { - if self.0 & (1 << bit) != 0 { - write!(f, "{} ", flag)?; - } - } - write!(f, "]") - } -} - -impl InstructionFormatter for GasFormatter { - fn format_instruction(&mut self, insn: &Instruction, out: &mut String) { - self.format(insn, out) - } -} - -impl Target for TargetImpl { - type Instruction = Instruction; - type InstructionFormatter = GasFormatter; - - fn disassemble( - window: &[u8], - ip: usize, - limit: usize, - ) -> Result, crate::Error> { - let mut instructions = vec![]; - let mut decoder = Decoder::with_ip(64, window, ip as _, DecoderOptions::NONE); - - while decoder.can_decode() && instructions.len() < limit { - let insn = decoder.decode(); - instructions.push((insn.ip() as usize, insn)); - } - - Ok(instructions) - } - - fn new_instruction_formatter() -> Self::InstructionFormatter { - let mut formatter = GasFormatter::new(); - formatter.options_mut().set_uppercase_hex(false); - formatter.options_mut().set_branch_leading_zeros(false); - formatter - } - - fn register_list(frame: &SavedFrame, out: &mut Vec<(String, u64)>) { - out.push(("rax".into(), frame.rax)); - out.push(("rcx".into(), frame.rcx)); - out.push(("rdx".into(), frame.rdx)); - out.push(("rbx".into(), frame.rbx)); - out.push(("rdi".into(), frame.rdi)); - out.push(("rsi".into(), frame.rsi)); - out.push(("rsp".into(), frame.user_sp)); - out.push(("rbp".into(), frame.rbp)); - out.push(("r8".into(), frame.r8)); - out.push(("r9".into(), frame.r9)); - out.push(("r10".into(), frame.r10)); - out.push(("r11".into(), frame.r11)); - out.push(("r12".into(), frame.r12)); - out.push(("r13".into(), frame.r13)); - out.push(("r14".into(), frame.r14)); - out.push(("r15".into(), frame.r15)); - } - - fn flags_register_as_display(frame: &SavedFrame) -> impl Display { - RflagsDisplay(frame.rflags) - } - - fn real_ip(frame: &SavedFrame) -> usize { - frame.user_ip as _ - } -} diff --git a/xtask/src/build/userspace.rs b/xtask/src/build/userspace.rs index 243c6955..6e07fc47 100644 --- a/xtask/src/build/userspace.rs +++ b/xtask/src/build/userspace.rs @@ -47,7 +47,7 @@ const PROGRAMS: &[(&str, &str)] = &[ // red ("red", "bin/red"), // rdb - // ("rdb", "bin/rdb"), + ("rdb", "bin/rdb"), // ("dyn-loader", "libexec/dyn-loader"), ];