Merge branch 'moar-gdb' into 'master'
Simplify EXEC catching + add signal handling See merge request redox-os/kernel!132
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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!();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
2
syscall
2
syscall
Submodule syscall updated: fcebe8f225...122878874d
Reference in New Issue
Block a user