wip: debugging

This commit is contained in:
Matthew LeVan 2024-01-22 21:49:24 -05:00
parent 43d145ac72
commit 5e44f2f94f
4 changed files with 42 additions and 16 deletions

View File

@ -375,11 +375,10 @@ extern "C" fn rust_callback(arg: *mut c_void) -> *mut c_void {
pub fn call_with_guard<F: FnMut() -> Result>(
f: F,
stack: *mut *mut c_void,
alloc: *mut *mut c_void,
stack: *const c_void,
alloc: *const c_void,
ret: *mut *mut c_void,
) -> Result {
eprintln!("call_with_guard");
let boxed_f = Box::new(f);
unsafe {
@ -988,8 +987,8 @@ pub fn interpret(context: &mut Context, mut subject: Noun, formula: Noun) -> Res
};
}
},
stack_p as *mut *mut c_void,
alloc_p as *mut *mut c_void,
stack_p as *const c_void,
alloc_p as *const c_void,
std::ptr::null_mut() as *mut *mut c_void,
)
})

View File

@ -21,12 +21,13 @@ volatile sig_atomic_t err = guard_sound;
guard_err _focus_guard() {
// Check for strange situations.
if (stack_p == NULL || alloc_p == NULL) {
fprintf(stderr, "guard: stack or alloc pointer is null\r\n");
return guard_weird;
}
// Unmark the old guard page.
void *old_guard_p = guard_p;
if (mprotect(old_guard_p, GD_PAGESIZE, PROT_READ | PROT_WRITE) == -1) {
if (old_guard_p != NULL && mprotect(old_guard_p, GD_PAGESIZE, PROT_READ | PROT_WRITE) == -1) {
return guard_armor;
}
@ -56,6 +57,7 @@ guard_err _focus_guard() {
guard_err _slash_guard(void *si_addr) {
if (si_addr >= guard_p && si_addr < guard_p + GD_PAGESIZE) {
fprintf(stderr, "guard: slash\r\n");
return _focus_guard();
}
@ -65,11 +67,11 @@ guard_err _slash_guard(void *si_addr) {
void _signal_handler(int sig, siginfo_t *si, void *unused) {
switch (sig) {
case SIGSEGV:
fprintf(stderr, "guard: caught sigsegv\r\n");
fprintf(stderr, "guard: segfault at %p\r\n", si->si_addr);
fprintf(stderr, "guard: guard at %p\r\n", guard_p);
err = _slash_guard(si->si_addr);
break;
case SIGINT:
fprintf(stderr, "guard: caught sigint\r\n");
err = guard_erupt;
break;
default:
@ -91,19 +93,25 @@ guard_err _register_handler() {
return guard_sound;
}
void guard(void *(*f)(void *), void *arg, void *const *const stack, void *const *const alloc, void **ret) {
stack_p = *stack;
alloc_p = *alloc;
void guard(void *(*f)(void *), void *arg, void *const stack, void *const alloc, void **ret) {
stack_p = stack;
alloc_p = alloc;
if (_register_handler() != guard_sound) {
err = guard_weird;
goto fail;
}
fprintf(stderr, "guard: installing guard page\r\n");
if (guard_p == NULL && (err = _focus_guard()) != guard_sound) {
goto fail;
if (guard_p == NULL) {
fprintf(stderr, "guard: installing guard page\r\n");
guard_err install_err = _focus_guard();
if (install_err != guard_sound) {
fprintf(stderr, "guard: failed to install guard page\r\n");
err = install_err;
goto fail;
}
}
fprintf(stderr, "guard: guard page installed at %p\r\n", guard_p);
*ret = f(arg);
@ -114,6 +122,7 @@ void guard(void *(*f)(void *), void *arg, void *const *const stack, void *const
return;
fail:
fprintf(stderr, "guard: error %d\r\n", err);
*ret = (void *) &err;
return;
}

View File

@ -30,7 +30,7 @@
* error will be written to the `ret` pointer. The caller is then responsible
* for handling this error and aborting with a `bail:meme`.
*/
void guard(void *(*f)(void *), void *arg, void *const *const stack, void *const *const alloc, void **ret);
void guard(void *(*f)(void *), void *arg, void *const stack, void *const alloc, void **ret);
typedef enum {
guard_sound = 0, // job's done

View File

@ -2,4 +2,22 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
extern "C" {
#[doc = " Execute the given closure `f` within the memory arena between the\n `stack` and `alloc` pointers, with guard page protection. Write either\n `f`'s succesful result or a `guard_err` to the given `ret` pointer.\n\n Memory\n ------\n The free memory arena between the `stack` and `alloc` pointers is part of a\n NockStack frame, which may either face east or west. If the frame faces\n east, the `stack` pointer will be greater than the `alloc` pointer. If it\n faces west, the `stack` pointer will be less than the `alloc` pointer.\n\n All the pages in the memory arena are marked clean (`PROT_READ | PROT_WRITE`)\n by default, with the exception of a single guard page in the middle of the\n arena, which is marked with `PROT_NONE`.\n\n Guard\n -----\n This function protects the free memory arena between the `stack` and `alloc`\n pointers with a guard page. A guard page is simply a single page of memory\n which is marked with `PROT_NONE`. Since all other pages are marked clean by\n default, a SIGSEGV will only be raised if the `f` function attempts to write\n to the guard page. When it does, the signal handler will attempt to re-center\n the guard page in the remaining free space left in the arena. If there is no\n more free space, then memory exhaustion has occurred and the `guard_spent`\n error will be written to the `ret` pointer. The caller is then responsible\n for handling this error and aborting with a `bail:meme`."]
pub fn guard(
f: ::std::option::Option<
unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void) -> *mut ::std::os::raw::c_void,
>,
arg: *mut ::std::os::raw::c_void,
stack: *const ::std::os::raw::c_void,
alloc: *const ::std::os::raw::c_void,
ret: *mut *mut ::std::os::raw::c_void,
);
}
pub const guard_err_guard_sound: guard_err = 0;
pub const guard_err_guard_armor: guard_err = 1;
pub const guard_err_guard_weird: guard_err = 2;
pub const guard_err_guard_spent: guard_err = 3;
pub const guard_err_guard_erupt: guard_err = 4;
pub type guard_err = ::std::os::raw::c_uint;