From a5379458cc384a8b50daf911099b994759114ce1 Mon Sep 17 00:00:00 2001 From: Alex Shelkovnykov Date: Sat, 3 Feb 2024 10:54:45 +0900 Subject: [PATCH 1/3] stack: add debug helper functions to NockStack --- rust/ares/src/mem.rs | 104 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/rust/ares/src/mem.rs b/rust/ares/src/mem.rs index 31f81c5..941d6ba 100644 --- a/rust/ares/src/mem.rs +++ b/rust/ares/src/mem.rs @@ -834,6 +834,110 @@ impl NockStack { } } } + + /** + * Debugging + * + * The below functions are useful for debugging NockStack issues. */ + + + /** + * Walk down the NockStack, printing frames. Absolutely no safety checks are peformed, as the + * purpose is to discover garbage data; just print pointers until the bottom of the NockStack + * (i.e. a null frame pointer) is encountered. Possible to crash, if a frame pointer gets + * written over. + */ + pub fn print_frames(&mut self) { + let mut fp = self.frame_pointer; + let mut sp = self.stack_pointer; + let mut ap = self.alloc_pointer; + let mut c = 0u64; + + eprintln!("\r start = {:p}", self.start); + + loop { + c += 1; + + eprintln!("\r {}:", c); + eprintln!("\r frame_pointer = {:p}", fp); + eprintln!("\r stack_pointer = {:p}", sp); + eprintln!("\r alloc_pointer = {:p}", ap); + + if fp.is_null() { + break; + } + + unsafe { + if fp < ap { + sp = *(fp.sub(STACK + 1) as *mut *mut u64); + ap = *(fp.sub(ALLOC + 1) as *mut *mut u64); + fp = *(fp.sub(FRAME + 1) as *mut *mut u64); + } else { + sp = *(fp.add(STACK) as *mut *mut u64); + ap = *(fp.add(ALLOC) as *mut *mut u64); + fp = *(fp.add(FRAME) as *mut *mut u64); + } + } + } + } + + /** + * Sanity check every frame of the NockStack. Most useful paired with a gdb session set to + * catch rust_panic. + */ + pub fn assert_sane(&mut self) { + let start = self.start; + let limit = unsafe { self.start.add(self.size) }; + let mut fp = self.frame_pointer; + let mut sp = self.stack_pointer; + let mut ap = self.alloc_pointer; + let mut ought_west: bool = fp < ap; + + loop { + // fp is null iff sp is null + assert!(!(fp.is_null() ^ sp.is_null())); + + // ap should never be null + assert!(!ap.is_null()); + + if fp.is_null() { + break; + } + + // all pointers must be between start and size + assert!(fp as *const u64 >= start); + assert!(fp as *const u64 <= limit); + assert!(sp as *const u64 >= start); + assert!(sp as *const u64 <= limit); + assert!(ap as *const u64 >= start); + assert!(ap as *const u64 <= limit); + + // frames should flip between east-west correctly + assert!((fp < ap) == ought_west); + + // sp should be between fp and ap + if ought_west { + assert!(sp >= fp); + assert!(sp < ap); + } else { + assert!(sp <= fp); + assert!(sp > ap); + } + + unsafe { + if ought_west { + sp = *(fp.sub(STACK + 1) as *mut *mut u64); + ap = *(fp.sub(ALLOC + 1) as *mut *mut u64); + fp = *(fp.sub(FRAME + 1) as *mut *mut u64); + } else { + sp = *(fp.add(STACK) as *mut *mut u64); + ap = *(fp.add(ALLOC) as *mut *mut u64); + fp = *(fp.add(FRAME) as *mut *mut u64); + } + } + ought_west = !ought_west; + } + } } impl NounAllocator for NockStack { From 2a040b565b16285183c21b8d50df5605b9785731 Mon Sep 17 00:00:00 2001 From: Alex Shelkovnykov Date: Fri, 2 Feb 2024 21:22:35 -0600 Subject: [PATCH 2/3] style: fix cargo fmt complaints --- rust/ares/src/mem.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/rust/ares/src/mem.rs b/rust/ares/src/mem.rs index 941d6ba..784124d 100644 --- a/rust/ares/src/mem.rs +++ b/rust/ares/src/mem.rs @@ -837,24 +837,23 @@ impl NockStack { /** * Debugging - * + * * The below functions are useful for debugging NockStack issues. */ - - /** - * Walk down the NockStack, printing frames. Absolutely no safety checks are peformed, as the - * purpose is to discover garbage data; just print pointers until the bottom of the NockStack - * (i.e. a null frame pointer) is encountered. Possible to crash, if a frame pointer gets - * written over. - */ + /** + * Walk down the NockStack, printing frames. Absolutely no safety checks are peformed, as the + * purpose is to discover garbage data; just print pointers until the bottom of the NockStack + * (i.e. a null frame pointer) is encountered. Possible to crash, if a frame pointer gets + * written over. + */ pub fn print_frames(&mut self) { let mut fp = self.frame_pointer; let mut sp = self.stack_pointer; let mut ap = self.alloc_pointer; let mut c = 0u64; - + eprintln!("\r start = {:p}", self.start); - + loop { c += 1; @@ -896,7 +895,7 @@ impl NockStack { loop { // fp is null iff sp is null assert!(!(fp.is_null() ^ sp.is_null())); - + // ap should never be null assert!(!ap.is_null()); From e02a232f2c43a38dbc0c5649ea1fc4cc2383fbfa Mon Sep 17 00:00:00 2001 From: Alex Shelkovnykov Date: Fri, 2 Feb 2024 21:24:38 -0600 Subject: [PATCH 3/3] style: same as prev commit --- rust/ares/src/mem.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rust/ares/src/mem.rs b/rust/ares/src/mem.rs index 784124d..7b65033 100644 --- a/rust/ares/src/mem.rs +++ b/rust/ares/src/mem.rs @@ -841,11 +841,11 @@ impl NockStack { * The below functions are useful for debugging NockStack issues. */ /** - * Walk down the NockStack, printing frames. Absolutely no safety checks are peformed, as the - * purpose is to discover garbage data; just print pointers until the bottom of the NockStack - * (i.e. a null frame pointer) is encountered. Possible to crash, if a frame pointer gets - * written over. - */ + * Walk down the NockStack, printing frames. Absolutely no safety checks are peformed, as the + * purpose is to discover garbage data; just print pointers until the bottom of the NockStack + * (i.e. a null frame pointer) is encountered. Possible to crash, if a frame pointer gets + * written over. + */ pub fn print_frames(&mut self) { let mut fp = self.frame_pointer; let mut sp = self.stack_pointer;