diff --git a/src/arch/x86_64/macros.rs b/src/arch/x86_64/macros.rs index 22fe5a3cf649ade69d1cb04180acdb1d5738cd5d..6271229b9ff277aa0c4ff1c84f480024e43a4e49 100644 --- a/src/arch/x86_64/macros.rs +++ b/src/arch/x86_64/macros.rs @@ -1,6 +1,5 @@ use core::mem; use syscall::data::IntRegisters; -use super::gdt; /// Print to console #[macro_export] @@ -216,24 +215,6 @@ pub struct InterruptStack { } impl InterruptStack { - pub fn new_usermode(ip: usize, sp: usize, arg: usize) -> Self { - // See which registers are set in start.rs, function `usermode` - Self { - fs: gdt::GDT_USER_TLS << 3 | 3, - preserved: PreservedRegisters::default(), - scratch: ScratchRegisters { - rdi: arg, - ..ScratchRegisters::default() - }, - iret: IretRegisters { - rip: ip, - cs: gdt::GDT_USER_CODE << 3 | 3, - rflags: 1 << 9, - rsp: sp, - ss: gdt::GDT_USER_DATA << 3 | 3, - }, - } - } pub fn dump(&self) { self.iret.dump(); self.scratch.dump(); @@ -323,6 +304,10 @@ impl InterruptStack { self.iret.rflags &= !(1 << 8); } } + /// Checks if the trap flag is enabled, see `set_singlestep` + pub fn is_singlestep(&self) -> bool { + self.iret.rflags & 1 << 8 == 1 << 8 + } } macro_rules! interrupt_push { diff --git a/src/arch/x86_64/start.rs b/src/arch/x86_64/start.rs index b2bc4e5fc1efc093626ed521fe285b5239b7117a..30425f0e2033b2adce9fe9b7ceefa3cc6c94841f 100644 --- a/src/arch/x86_64/start.rs +++ b/src/arch/x86_64/start.rs @@ -3,7 +3,7 @@ /// It must create the IDT with the correct entries, those entries are /// defined in other files inside of the `arch` module -use core::{slice, mem, ptr}; +use core::slice; use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use crate::allocator; @@ -17,7 +17,6 @@ use crate::gdt; use crate::idt; use crate::interrupt; use crate::log; -use crate::macros::InterruptStack; use crate::memory; use crate::paging; @@ -234,7 +233,12 @@ pub unsafe extern fn kstart_ap(args_ptr: *const KernelArgsAp) -> ! { } #[naked] -pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! { +pub unsafe fn usermode(ip: usize, sp: usize, arg: usize, singlestep: bool) -> ! { + let mut flags = 1 << 9; + if singlestep { + flags |= 1 << 8; + } + asm!("push r10 push r11 push r12 @@ -244,7 +248,7 @@ pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! { : // No output : "{r10}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment "{r11}"(sp), // Stack pointer - "{r12}"(1 << 9), // Flags - Set interrupt enable flag + "{r12}"(flags), // Flags - Set interrupt enable flag "{r13}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment "{r14}"(ip), // IP "{r15}"(arg) // Argument @@ -284,31 +288,3 @@ pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! { : "intel", "volatile"); unreachable!(); } - -#[naked] -pub unsafe fn usermode_interrupt_stack(stack: InterruptStack) -> ! { - // Push fake stack to the actual stack - let rsp: usize; - asm!("sub rsp, $1" : "={rsp}"(rsp) : "r"(mem::size_of::<InterruptStack>()) : : "intel", "volatile"); - ptr::write(rsp as *mut InterruptStack, stack); - - // Unmap kernel - pti::unmap(); - - // Set up floating point and TLS - asm!("mov ds, r14d - mov es, r14d - mov fs, r15d - mov gs, r14d - fninit" - : // No output because it never returns - : "{r14}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment - "{r15}"(gdt::GDT_USER_TLS << 3 | 3) // TLS segment - : "ds", "es", "fs", "gs" - : "intel", "volatile"); - - // Go to usermode - interrupt_pop!(); - iret!(); - unreachable!(); -} diff --git a/src/context/signal.rs b/src/context/signal.rs index 78e165af4f352453d7fcc7da46a5a5d223f00fe2..05d3ff749467360a3bc44136ad9591d318839502 100644 --- a/src/context/signal.rs +++ b/src/context/signal.rs @@ -105,6 +105,15 @@ pub extern "C" fn signal_handler(sig: usize) { } else { // println!("Call {:X}", handler); + let singlestep = { + let contexts = contexts(); + let context = contexts.current().expect("context::signal_handler userspace not inside of context"); + let context = context.read(); + unsafe { + ptrace::regs_for(&context).map(|s| s.is_singlestep()).unwrap_or(false) + } + }; + unsafe { let mut sp = crate::USER_SIGSTACK_OFFSET + crate::USER_SIGSTACK_SIZE - 256; @@ -113,7 +122,7 @@ pub extern "C" fn signal_handler(sig: usize) { sp -= mem::size_of::<usize>(); *(sp as *mut usize) = restorer; - usermode(handler, sp, sig); + usermode(handler, sp, sig, singlestep); } } diff --git a/src/context/switch.rs b/src/context/switch.rs index 6e10825fcab4326d10a02bbf88d758b35740b773..851655757f6df75bd36cc870d719e107f1768bcc 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -1,10 +1,11 @@ use core::sync::atomic::Ordering; -use crate::context::{arch, contexts, Context, Status, CONTEXT_ID}; use crate::context::signal::signal_handler; +use crate::context::{arch, contexts, Context, Status, CONTEXT_ID}; use crate::gdt; -use crate::interrupt; use crate::interrupt::irq::PIT_TICKS; +use crate::interrupt; +use crate::ptrace; use crate::time; unsafe fn update(context: &mut Context, cpu_id: usize) { @@ -16,6 +17,8 @@ unsafe fn update(context: &mut Context, cpu_id: usize) { // Restore from signal, must only be done from another context to avoid overwriting the stack! if context.ksig_restore && ! context.running { + let was_singlestep = ptrace::regs_for(context).map(|s| s.is_singlestep()).unwrap_or(false); + let ksig = context.ksig.take().expect("context::switch: ksig not set with ksig_restore"); context.arch = ksig.0; @@ -33,6 +36,11 @@ unsafe fn update(context: &mut Context, cpu_id: usize) { context.ksig_restore = false; + // Keep singlestep flag across jumps + if let Some(regs) = ptrace::regs_for_mut(context) { + regs.set_singlestep(was_singlestep); + } + context.unblock(); } diff --git a/src/syscall/process.rs b/src/syscall/process.rs index e27576fd3e248ec542b0b40df67034f97ec23686..2da33bd2a5e698a17cb76185e948a889d7ddc8a7 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -6,7 +6,6 @@ use core::{intrinsics, mem}; use core::ops::DerefMut; use spin::Mutex; -use crate::arch::macros::InterruptStack; use crate::context::file::FileDescriptor; use crate::context::{ContextId, WaitpidKey}; use crate::context; @@ -21,14 +20,14 @@ use crate::paging::temporary_page::TemporaryPage; use crate::paging::{ActivePageTable, InactivePageTable, Page, VirtualAddress, PAGE_SIZE}; use crate::{ptrace, syscall}; use crate::scheme::FileHandle; -use crate::start::{usermode, usermode_interrupt_stack}; +use crate::start::usermode; use crate::syscall::data::{SigAction, Stat}; use crate::syscall::error::*; -use crate::syscall::flag::{CloneFlags, CLONE_FILES, CLONE_FS, CLONE_SIGHAND, - CLONE_STACK, CLONE_VFORK, CLONE_VM, MapFlags, PtraceFlags, PROT_EXEC, - PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, PTRACE_STOP_EXIT, SigActionFlags, - SIG_BLOCK, SIG_DFL, SIG_SETMASK, SIG_UNBLOCK, SIGCONT, SIGTERM, WaitFlags, - WCONTINUED, WNOHANG,WUNTRACED, wifcontinued, wifstopped}; +use crate::syscall::flag::{wifcontinued, wifstopped, CloneFlags, CLONE_FILES, + CLONE_FS, CLONE_SIGHAND, CLONE_STACK, CLONE_VFORK, CLONE_VM, MapFlags, + PROT_EXEC, PROT_READ, PROT_WRITE, PTRACE_EVENT_CLONE, PTRACE_STOP_EXIT, + SigActionFlags, SIG_BLOCK, SIG_DFL, SIG_SETMASK, SIG_UNBLOCK, SIGCONT, SIGTERM, + WaitFlags, WCONTINUED, WNOHANG,WUNTRACED}; use crate::syscall::ptrace_event; use crate::syscall::validate::{validate_slice, validate_slice_mut}; @@ -661,6 +660,7 @@ fn fexec_noreturn( vars: Box<[Box<[u8]>]> ) -> ! { let entry; + let singlestep; let mut sp = crate::USER_STACK_OFFSET + crate::USER_STACK_SIZE - 256; { @@ -669,6 +669,10 @@ fn fexec_noreturn( let context_lock = contexts.current().ok_or(Error::new(ESRCH)).expect("exec_noreturn pid not found"); let mut context = context_lock.write(); + singlestep = unsafe { + ptrace::regs_for(&context).map(|s| s.is_singlestep()).unwrap_or(false) + }; + context.name = Arc::new(Mutex::new(name)); empty(&mut context, false); @@ -712,8 +716,8 @@ fn fexec_noreturn( unsafe { // Copy file data intrinsics::copy((elf.data.as_ptr() as usize + segment.p_offset as usize) as *const u8, - segment.p_vaddr as *mut u8, - segment.p_filesz as usize); + segment.p_vaddr as *mut u8, + segment.p_filesz as usize); } let mut flags = EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE; @@ -900,22 +904,8 @@ fn fexec_noreturn( } } - // Create dummy stack for ptrace to read from - let mut regs = InterruptStack::new_usermode(entry, sp, 0); - - // ptrace breakpoint - let was_traced = { - let _guard = ptrace::set_process_regs(&mut regs); - ptrace::breakpoint_callback(PtraceFlags::PTRACE_STOP_EXEC, None).is_some() - }; - - if !was_traced { - // Go to usermode, fast route - unsafe { usermode(entry, sp, 0) } - } else { - // Go to usermode, take ptrace-modified stack into account - unsafe { usermode_interrupt_stack(regs) } - } + // Go to usermode + unsafe { usermode(entry, sp, 0, singlestep) } } pub fn fexec_kernel(fd: FileHandle, args: Box<[Box<[u8]>]>, vars: Box<[Box<[u8]>]>, name_override_opt: Option<Box<[u8]>>) -> Result<usize> { diff --git a/syscall b/syscall index fcebe8f225142830fa5880a27d9faa6ed6b2aeb8..122878874d3f4fee0fd1f19b8dc2b07d84d5df8b 160000 --- a/syscall +++ b/syscall @@ -1 +1 @@ -Subproject commit fcebe8f225142830fa5880a27d9faa6ed6b2aeb8 +Subproject commit 122878874d3f4fee0fd1f19b8dc2b07d84d5df8b