//! Defines a simple panic handler which handles stack traces as required.

use core::{arch::asm, panic::PanicInfo};

use alloc::string::ToString;
use fallible_iterator::FallibleIterator;
use gimli::{Register, X86_64};

use super::unwinder::Unwinder;
use crate::{
    hcf,
    prelude::*,
    std::unwind::{UNWINDER, eh_info::ELF, unwinder::RegisterSet},
};

#[panic_handler]
/// A basic panic handler which can produce a helpful stack trace.
pub fn panic_handler(info: &PanicInfo<'_>) -> ! {
    debugln!("Kernel panic: {}", info);

    let mut rip: u64;
    let mut rsp: u64;
    unsafe {
        asm!("lea {0}, [rip]", 
        "mov {1}, rsp",
        out(reg) rip, out(reg) rsp);
    }

    let mut unwinder = UNWINDER.lock();
    unwinder.regs.set_pc(rip);
    unwinder.regs.set_stack_ptr(rsp);

    while let Some(call_frame) = unwinder.next().unwrap_or_else(|err| {
        // If an unwind error occurred.
        debugln!("{:?}", err);
        hcf()
    }) {
        serial_println!("Got frame: {:x?}", call_frame);
        let Some((symtab, strtab)) =
            ELF.get_symbol_table().unwrap_or_else(|e| {
                debugln!("{:?}", e);
                hcf()
            })
        else {
            // TODO: Omit symbol names but just print addresses.
            debugln!("Didn't find symtab and strtab!");
            hcf()
        };

        // let sym_name = symtab.get(call_frame.pc as usize).unwrap();
    }

    crate::hcf()
}
