Merge branch 'no-tcb' into 'master'

Handle panic without TCB

See merge request redox-os/relibc!1530
This commit is contained in:
Jeremy Soller
2026-07-07 06:45:42 -06:00
9 changed files with 82 additions and 108 deletions
-33
View File
@@ -98,36 +98,3 @@ impl<Os> GenericTcb<Os> {
unsafe { Some(&mut *Self::current_ptr()?) }
}
}
pub fn panic_notls(_msg: impl core::fmt::Display) -> ! {
// TODO: actually print _msg, perhaps by having panic_notls take a `T: DebugBackend` that can
// propagate until called by e.g. relibc start
core::intrinsics::abort();
}
pub trait ExpectTlsFree {
type Unwrapped;
fn expect_notls(self, msg: &str) -> Self::Unwrapped;
}
impl<T, E: core::fmt::Debug> ExpectTlsFree for Result<T, E> {
type Unwrapped = T;
fn expect_notls(self, msg: &str) -> T {
match self {
Ok(t) => t,
Err(err) => panic_notls(format_args!(
"{msg}: expect failed for Result with err: {err:?}",
)),
}
}
}
impl<T> ExpectTlsFree for Option<T> {
type Unwrapped = T;
fn expect_notls(self, msg: &str) -> T {
match self {
Some(t) => t,
None => panic_notls(format_args!("{msg}: expect failed for Option")),
}
}
}
+6 -8
View File
@@ -6,8 +6,6 @@
use core::cell::UnsafeCell;
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
use generic_rt::ExpectTlsFree; // not used on aarch64 or riscv64
use generic_rt::GenericTcb;
use redox_protocols::protocol::ProcMeta;
use syscall::Sigcontrol;
@@ -94,13 +92,13 @@ pub unsafe fn tcb_activate(tcb: &RtTcb, tls_end: usize, _tls_len: usize) {
let mut env = syscall::EnvRegisters::default();
let file_fd = crate::sys::dup_into_upper_raw(tcb.thread_fd().as_raw_fd(), b"regs/env")
.expect_notls("failed to open handle for process registers");
.expect("failed to open handle for process registers");
syscall::read(file_fd, &mut env).expect_notls("failed to read gsbase");
syscall::read(file_fd, &mut env).expect("failed to read gsbase");
env.gsbase = tls_end as u32;
syscall::write(file_fd, &env).expect_notls("failed to write gsbase");
syscall::write(file_fd, &env).expect("failed to write gsbase");
let _ = crate::sys::close_raw(file_fd);
@@ -114,13 +112,13 @@ pub unsafe fn tcb_activate(tcb: &RtTcb, tls_end_and_tcb_start: usize, _tls_len:
let mut env = syscall::EnvRegisters::default();
let file_fd = crate::sys::dup_into_upper_raw(tcb.thread_fd().as_raw_fd(), b"regs/env")
.expect_notls("failed to open handle for process registers");
.expect("failed to open handle for process registers");
syscall::read(file_fd, &mut env).expect_notls("failed to read fsbase");
syscall::read(file_fd, &mut env).expect("failed to read fsbase");
env.fsbase = tls_end_and_tcb_start as u64;
syscall::write(file_fd, &env).expect_notls("failed to write fsbase");
syscall::write(file_fd, &env).expect("failed to write fsbase");
let _ = crate::sys::close_raw(file_fd);
+1 -1
View File
@@ -541,7 +541,7 @@ pub struct TmpDisableSignalsGuard {
active: bool,
}
/// Used to prevent EINTR from appearing across all syscall
/// Used to disable jumping to signal handler while the guard active
pub fn tmp_disable_signals() -> TmpDisableSignalsGuard {
if !crate::TLS_ACTIVATED.load(Ordering::Relaxed) {
return TmpDisableSignalsGuard { active: false };
+10 -13
View File
@@ -28,8 +28,6 @@ pub mod linker;
pub mod start;
pub mod tcb;
pub use generic_rt::{ExpectTlsFree, panic_notls};
static mut STATIC_TCB_MASTER: Master = Master {
ptr: ptr::null_mut(),
image_size: 0,
@@ -66,9 +64,9 @@ fn static_init(
auxv = unsafe { auxv.add(1) };
}
let phdr = phdr_opt.expect_notls("failed to find AT_PHDR");
let phent = phent_opt.expect_notls("failed to find AT_PHENT");
let phnum = phnum_opt.expect_notls("failed to find AT_PHNUM");
let phdr = phdr_opt.expect("failed to find AT_PHDR");
let phent = phent_opt.expect("failed to find AT_PHENT");
let phnum = phnum_opt.expect("failed to find AT_PHNUM");
for i in 0..phnum {
let ph_addr = phdr + phent * i;
@@ -95,7 +93,7 @@ fn static_init(
ph.p_vaddr(endian) as usize,
)
},
_ => panic_notls(format_args!("unknown AT_PHENT size {}", phent)),
_ => panic!("unknown AT_PHENT size {}", phent),
};
let page_size = Sys::getpagesize();
@@ -115,11 +113,10 @@ fn static_init(
STATIC_TCB_MASTER.image_size = p_filesz;
STATIC_TCB_MASTER.offset = valign;
let tcb = Tcb::new(vsize).expect_notls("failed to allocate TCB");
let tcb = Tcb::new(vsize).expect("failed to allocate TCB");
tcb.masters_ptr = ptr::addr_of_mut!(STATIC_TCB_MASTER);
tcb.masters_len = mem::size_of::<Master>();
tcb.copy_masters()
.expect_notls("failed to copy TLS master data");
tcb.copy_masters().expect("failed to copy TLS master data");
tcb.activate(
#[cfg(target_os = "redox")]
Some(thr_fd),
@@ -160,9 +157,9 @@ pub unsafe fn init(
{
let file = thr_fd
.dup_into_upper(b"regs/env")
.expect_notls("failed to open handle for process registers");
.expect("failed to open handle for process registers");
file.read(&mut env).expect_notls("failed to read gsbase");
file.read(&mut env).expect("failed to read gsbase");
}
tp = env.gsbase as usize;
@@ -174,9 +171,9 @@ pub unsafe fn init(
{
let file = thr_fd
.dup_into_upper(b"regs/env")
.expect_notls("failed to open handle for process registers");
.expect("failed to open handle for process registers");
file.read(&mut env).expect_notls("failed to read fsbase");
file.read(&mut env).expect("failed to read fsbase");
}
tp = env.fsbase as usize;
+14 -16
View File
@@ -41,8 +41,6 @@ use super::{
tcb::Tcb,
};
use generic_rt::ExpectTlsFree;
#[cfg(target_pointer_width = "32")]
pub const SIZEOF_EHDR: usize = 52;
@@ -192,13 +190,13 @@ pub unsafe extern "C" fn relibc_ld_so_start(
}
}
let at_phdr = at_phdr.expect_notls("`AT_PHDR` must be present");
let at_phnum = at_phnum.expect_notls("`AT_PHNUM` must be present if `AT_PHDR` is");
let at_phent = at_phent.expect_notls("`AT_PHENT` must be present if `AT_PHDR` is");
let at_phdr = at_phdr.expect("`AT_PHDR` must be present");
let at_phnum = at_phnum.expect("`AT_PHNUM` must be present if `AT_PHDR` is");
let at_phent = at_phent.expect("`AT_PHENT` must be present if `AT_PHDR` is");
assert!(!at_phdr.is_null() && at_phnum != 0 && at_phent == size_of::<ProgramHeader>());
let phdrs = unsafe { slice::from_raw_parts(at_phdr, at_phnum) };
let at_entry = at_entry.expect_notls("`AT_ENTRY` must be present");
let at_entry = at_entry.expect("`AT_ENTRY` must be present");
let at_base = at_base.unwrap_or_default();
let self_base = if at_base != 0 {
@@ -252,7 +250,7 @@ pub unsafe extern "C" fn relibc_ld_so_start(
base_addr: usize,
) -> &'a [T] {
if let Some(ptr) = ptr {
let len = len.expect_notls("dynamic entry was present without it's corresponding size");
let len = len.expect("dynamic entry was present without it's corresponding size");
unsafe { core::slice::from_raw_parts(ptr.byte_add(base_addr), len) }
} else {
&[]
@@ -315,7 +313,7 @@ fn stage2(
let auxv = sp.auxv().cast();
#[cfg(target_os = "redox")]
let thr_fd = crate::platform::get_auxv_raw(auxv, redox_rt::auxv_defs::AT_REDOX_THR_FD)
.expect_notls("no thread fd present");
.expect("no thread fd present");
#[cfg(target_os = "redox")]
{
@@ -324,43 +322,43 @@ fn stage2(
sp.auxv().cast(),
redox_rt::auxv_defs::AT_REDOX_FILETABLE_FD,
)
.expect_notls("no filetable fd present");
.expect("no filetable fd present");
let filetable_guard = redox_rt::proc::FdGuard::new(filetable_fd)
.to_upper()
.expect_notls("failed to move filetable fd to upper table");
.expect("failed to move filetable fd to upper table");
*redox_rt::current_filetable() =
redox_rt::sys::FdTbl::from_binary_fd(filetable_guard)
.expect_notls("failed to initialize FILETABLE");
.expect("failed to initialize FILETABLE");
}
}
let tcb = Tcb::new(0).expect_notls("[ld.so]: failed to allocate bootstrap TCB");
let tcb = Tcb::new(0).expect("[ld.so]: failed to allocate bootstrap TCB");
tcb.activate(
#[cfg(target_os = "redox")]
Some(
redox_rt::proc::FdGuard::new(thr_fd)
.to_upper()
.expect_notls("failed to move thread fd to upper table"),
.expect("failed to move thread fd to upper table"),
),
);
#[cfg(target_os = "redox")]
{
let proc_fd =
crate::platform::get_auxv_raw(auxv, redox_rt::auxv_defs::AT_REDOX_PROC_FD)
.expect_notls("no proc fd present");
.expect("no proc fd present");
let ns_fd = crate::platform::get_auxv_raw(auxv, redox_rt::auxv_defs::AT_REDOX_NS_FD)
.filter(|&fd| fd != usize::MAX)
.map(|fd| {
redox_rt::proc::FdGuard::new(fd)
.to_upper()
.expect_notls("failed to move ns fd to upper table")
.expect("failed to move ns fd to upper table")
});
redox_rt::initialize(
redox_rt::proc::FdGuard::new(proc_fd)
.to_upper()
.expect_notls("failed to move proc fd to upper table"),
.expect("failed to move proc fd to upper table"),
ns_fd,
);
redox_rt::signal::setup_sighandler(&tcb.os_specific, true);
+6 -26
View File
@@ -48,6 +48,7 @@ pub mod io;
pub mod iter;
pub mod ld_so;
pub mod out;
pub mod panic;
pub mod platform;
pub mod pthread;
pub mod raw_cell;
@@ -59,21 +60,11 @@ use crate::platform::{Allocator, NEWALLOCATOR};
#[global_allocator]
static ALLOCATOR: Allocator = NEWALLOCATOR;
#[unsafe(no_mangle)]
pub extern "C" fn relibc_panic(pi: &::core::panic::PanicInfo) -> ! {
use core::fmt::Write;
let mut w = platform::FileWriter::new(2);
let _ = w.write_fmt(format_args!("RELIBC PANIC: {}\n", pi));
core::intrinsics::abort();
}
#[cfg(not(test))]
#[panic_handler]
#[linkage = "weak"]
pub fn rust_begin_unwind(pi: &::core::panic::PanicInfo) -> ! {
relibc_panic(pi)
crate::panic::relibc_panic(pi)
}
#[cfg(not(test))]
@@ -87,17 +78,11 @@ pub extern "C" fn rust_eh_personality() {}
#[allow(improper_ctypes_definitions)]
#[unsafe(no_mangle)]
pub extern "C" fn rust_oom(layout: ::core::alloc::Layout) -> ! {
// Layout not FFI-safe?
use core::fmt::Write;
let mut w = platform::FileWriter::new(2);
let _ = w.write_fmt(format_args!(
"RELIBC OOM: {} bytes aligned to {} bytes\n",
panic!(
"RELIBC OOM: {} bytes aligned to {} bytes",
layout.size(),
layout.align()
));
core::intrinsics::abort();
);
}
#[cfg(not(test))]
@@ -105,10 +90,5 @@ pub extern "C" fn rust_oom(layout: ::core::alloc::Layout) -> ! {
#[linkage = "weak"]
#[unsafe(no_mangle)]
pub extern "C" fn _Unwind_Resume() -> ! {
use core::fmt::Write;
let mut w = platform::FileWriter::new(2);
let _ = w.write_str("_Unwind_Resume\n");
core::intrinsics::abort();
panic!("_Unwind_Resume")
}
+37
View File
@@ -0,0 +1,37 @@
use core::fmt::Write;
#[unsafe(no_mangle)]
pub extern "C" fn relibc_panic(pi: &::core::panic::PanicInfo) -> ! {
use core::fmt::Write;
let mut w = PanicWriter::new();
let _ = w.write_fmt(format_args!("RELIBC PANIC: {}\n", pi));
core::intrinsics::abort();
}
struct PanicWriter;
impl PanicWriter {
pub fn new() -> Self {
Self
}
}
impl Write for PanicWriter {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
// Cannot use Sys::write, Tcb might not be available
#[cfg(target_os = "redox")]
{
// TODO: init stderr ourself if it not ready.
// Workaround: If stderr is not being prepared,
// add debugging log at kernel write() syscall
let _ = syscall::write(2, s.as_bytes());
return Ok(());
}
// Non-redox platforms can directly write to stderr
let mut w = crate::platform::FileWriter::new(2);
w.write_str(s)
}
}
+3 -3
View File
@@ -13,7 +13,7 @@ use redox_rt::RtTcb;
use crate::{
error::Errno,
header::{errno::*, pthread as header, sched::sched_param, sys_mman},
ld_so::{ExpectTlsFree, tcb::Tcb},
ld_so::tcb::Tcb,
platform::{Pal, Sys, types::*},
};
@@ -47,7 +47,7 @@ pub unsafe fn init() {
thread.stack_size = STACK_SIZE;
}
let current_tcb = unsafe { Tcb::current() }.expect_notls("no TCB present for main thread");
let current_tcb = unsafe { Tcb::current() }.expect("no TCB present for main thread");
current_tcb.pthread = thread;
unsafe {
current_tcb.pthread.tcb_selfref.get().write(current_tcb);
@@ -221,7 +221,7 @@ unsafe extern "C" fn new_thread_shim(
tcb: *mut Tcb,
synchronization_mutex: *const Mutex<u64>,
) -> ! {
let tcb = unsafe { tcb.as_mut() }.expect_notls("non-null TLS is required");
let tcb = unsafe { tcb.as_mut() }.expect("non-null TLS is required");
#[cfg(not(target_os = "redox"))]
{
+5 -8
View File
@@ -3,9 +3,6 @@
use alloc::{boxed::Box, vec::Vec};
use core::{intrinsics, ptr};
#[cfg(target_os = "redox")]
use generic_rt::ExpectTlsFree;
use crate::{
ALLOCATOR,
header::{libgen, stdio, stdlib},
@@ -169,10 +166,10 @@ pub unsafe extern "C" fn relibc_start_v1(
unsafe {
crate::platform::get_auxv_raw(sp.auxv().cast(), redox_rt::auxv_defs::AT_REDOX_THR_FD)
}
.expect_notls("no thread fd present"),
.expect("no thread fd present"),
)
.to_upper()
.expect_notls("failed to move thread fd to upper table");
.expect("failed to move thread fd to upper table");
#[cfg(target_os = "redox")]
{
@@ -183,12 +180,12 @@ pub unsafe extern "C" fn relibc_start_v1(
redox_rt::auxv_defs::AT_REDOX_FILETABLE_FD,
)
}
.expect_notls("no filetable fd present");
.expect("no filetable fd present");
let filetable_guard = redox_rt::proc::FdGuard::new(filetable_fd)
.to_upper()
.expect_notls("failed to move filetable fd to upper table");
.expect("failed to move filetable fd to upper table");
*redox_rt::current_filetable() = redox_rt::sys::FdTbl::from_binary_fd(filetable_guard)
.expect_notls("failed to initialize FILETABLE");
.expect("failed to initialize FILETABLE");
}
}