#![no_std]
#![no_main]
extern crate alloc;
use core::mem::MaybeUninit;
use esp_backtrace as _;
use core::cell::RefCell;
use critical_section::Mutex;
use hal::{
clock::ClockControl,
interrupt,
peripherals::{Peripherals, Interrupt},
prelude::*,
Delay,
assist_debug::DebugAssist
};
use log::{error, info};
use alloc::vec::Vec;
#[global_allocator]
static ALLOCATOR: esp_alloc::EspHeap = esp_alloc::EspHeap::empty();
fn init_heap() {
const HEAP_SIZE: usize = 300 * 1024; // Define heap size
static mut HEAP: MaybeUninit<[u8; HEAP_SIZE]> = MaybeUninit::uninit();
unsafe {
ALLOCATOR.init(HEAP.as_mut_ptr() as *mut u8, HEAP_SIZE);
}
}
// Static variable to hold DebugAssist
static DA: Mutex<RefCell<Option<DebugAssist<'static>>>> = Mutex::new(RefCell::new(None));
fn install_stack_guard(mut da: DebugAssist<'static>, safe_area_size: u32) {
extern "C" {
static mut _stack_end: u32;
static mut _stack_start: u32;
}
let stack_low = unsafe { &mut _stack_end as *mut _ as u32 };
let stack_high = unsafe { &mut _stack_start as *mut _ as u32 };
info!("Safe stack {} bytes", stack_high - stack_low - safe_area_size);
da.enable_region0_monitor(stack_low, stack_low + safe_area_size, true, true);
critical_section::with(|cs| DA.borrow_ref_mut(cs).replace(da));
interrupt::enable(Interrupt::ASSIST_DEBUG, interrupt::Priority::Priority1).unwrap();
}
#[entry]
fn main() -> ! {
init_heap();
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::max(system.clock_control).freeze();
let mut delay = Delay::new(&clocks);
esp_println::logger::init_logger_from_env();
// get the debug assist driver
let da = DebugAssist::new(peripherals.ASSIST_DEBUG);
install_stack_guard(da, 4096); // 4 KB safe area
recursive_stack_and_heap_allocation(1, 1024); // Initial depth and allocation size
loop {
delay.delay_ms(1000u32);
}
}
fn recursive_stack_and_heap_allocation(depth: usize, allocation_size: usize) {
// Allocate some data on the stack
let mut stack_data = [0u8; 1024]; // 1 KB of data on the stack
stack_data[0] = 1; // Access the array to ensure it's not optimized out
// Heap allocation
let mut test_vec:Vec<u8> = Vec::new();
test_vec.resize(allocation_size, 0);
test_vec[0] = 1; // Access the array to ensure it's not optimized out
info!("Depth: {}, Stack usage: {} bytes, Heap allocation: {}, Memory - used: {}; free: {}",
depth, depth * 1024, allocation_size, ALLOCATOR.used(), ALLOCATOR.free());
if depth > 1000 {
return; // Limit recursion depth to prevent stack overflow
}
recursive_stack_and_heap_allocation(depth + 1, allocation_size);
// Keep allocation size the same, since variables are not going out of scope in recursion
}
#[interrupt]
fn ASSIST_DEBUG() {
critical_section::with(|cs| {
error!("\n\nPossible Stack Overflow Detected");
let mut da = DA.borrow_ref_mut(cs);
let da = da.as_mut().unwrap();
if da.is_region0_monitor_interrupt_set() {
let pc = da.get_region_monitor_pc();
info!("PC = 0x{:x}", pc);
da.clear_region0_monitor_interrupt();
da.disable_region0_monitor();
loop {}
}
});
}