Skip to main content

kernel/
debug.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Support for in-kernel debugging.
6//!
7//! For printing, this module uses an internal buffer to write the strings into.
8//! If you are writing and the buffer fills up, you can make the size of
9//! `output_buffer` larger.
10//!
11//! Before debug interfaces can be used, the board file must assign them
12//! hardware:
13//!
14//! ```ignore
15//! let debug_gpios = static_init!(
16//!     [&'static dyn kernel::hil::gpio::Pin; 2],
17//!     [
18//!         &sam4l::gpio::PA[13],
19//!         &sam4l::gpio::PA[15],
20//!     ]
21//! );
22//! kernel::debug::initialize_debug_gpio::<
23//!     <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
24//! >();
25//! kernel::debug::assign_gpios(debug_gpios);
26//!
27//! components::debug_writer::DebugWriterComponent::new(
28//!     uart_mux,
29//!     create_capability!(kernel::capabilities::SetDebugWriterCapability)
30//! )
31//! .finalize(components::debug_writer_component_static!());
32//! ```
33//!
34//! An alternative to using the default `DebugWriterComponent`, which defaults
35//! to sending over UART, is to implement a custom [`DebugWriter`] that can be
36//! used for other types of output. For example a simple "endless" FIFO with
37//! fixed "push" address:
38//!
39//! ```ignore
40//! use kernel::debug::DebugWriter;
41//!
42//! pub struct SyncDebugWriter;
43//!
44//! impl DebugWriter for SyncDebugWriter {
45//!    fn write(&self, buf: &[u8], _overflow: &[u8]) -> usize {
46//!        let out_reg = 0x4000 as *mut u8; // Replace with the actual address of the FIFO
47//!        for c in buf.iter() {
48//!            unsafe { out_reg.write_volatile(*c) };
49//!        }
50//!        buf.len()
51//!    }
52//!
53//!    fn available_len(&self) -> usize {
54//!        usize::MAX
55//!    }
56//!
57//!    fn to_write_len(&self) -> usize {
58//!        0
59//!    }
60//!
61//!    fn publish(&self) -> usize {
62//!        0
63//!    }
64//!
65//!    fn flush(&self, _writer: &mut dyn IoWrite) { }
66//! }
67//! ```
68//! And instantiate it in the main board file:
69//!
70//! ```ignore
71//! let debug_writer = static_init!(
72//!     utils::SyncDebugWriter,
73//!     utils::SyncDebugWriter
74//! );
75//!
76//! kernel::debug::initialize_debug_writer_wrapper::<
77//!     <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider
78//! >();
79//!
80//! kernel::debug::set_debug_writer_wrapper(
81//!     debug_writer,
82//!     create_capability!(kernel::capabilities::SetDebugWriterCapability)
83//! );
84//! ```
85//!
86//! Example
87//! -------
88//!
89//! ```no_run
90//! # use kernel::{debug, debug_gpio, debug_verbose};
91//! # fn main() {
92//! # let i = 42;
93//! debug!("Yes the code gets here with value {}", i);
94//! debug_verbose!("got here"); // Includes message count, file, and line.
95//!
96//! debug_gpio!(0, toggle); // Toggles the first debug GPIO.
97//!
98//! # }
99//! ```
100//!
101//! ```text
102//! Yes the code gets here with value 42
103//! TOCK_DEBUG(0): /tock/capsules/src/sensys.rs:24: got here
104//! ```
105
106use core::cell::Cell;
107use core::fmt::{Arguments, Write, write};
108use core::panic::PanicInfo;
109use core::str;
110
111use crate::capabilities::SetDebugWriterCapability;
112use crate::hil;
113use crate::platform::chip::Chip;
114use crate::platform::chip::PanicWriter;
115use crate::platform::chip::ThreadIdProvider;
116use crate::process::ProcessPrinter;
117use crate::process::ProcessSlot;
118use crate::processbuffer::ReadableProcessSlice;
119use crate::utilities::binary_write::BinaryToWriteWrapper;
120use crate::utilities::cells::MapCell;
121use crate::utilities::cells::NumericCellExt;
122use crate::utilities::io_write::IoWrite;
123use crate::utilities::single_thread_value::SingleThreadValue;
124
125///////////////////////////////////////////////////////////////////
126// panic! support routines
127
128/// Resources needed by the main panic routines.
129pub struct PanicResources<C: Chip + 'static, PP: ProcessPrinter + 'static> {
130    /// The array of process slots.
131    pub processes: MapCell<&'static [ProcessSlot]>,
132    /// The board-specific chip object.
133    pub chip: MapCell<&'static C>,
134    /// The tool for printing process details.
135    pub printer: MapCell<&'static PP>,
136}
137
138impl<C: Chip, PP: ProcessPrinter> PanicResources<C, PP> {
139    /// Create a new [`PanicResources`] with nothing stored.
140    pub const fn new() -> Self {
141        Self {
142            processes: MapCell::empty(),
143            chip: MapCell::empty(),
144            printer: MapCell::empty(),
145        }
146    }
147}
148
149/// Tock panic routine, without the infinite LED-blinking loop.
150///
151/// This is useful for boards which do not feature LEDs to blink or want to
152/// implement their own behavior. This method returns after performing the panic
153/// dump.
154///
155/// After this method returns, the system is no longer in a well-defined state.
156/// Care must be taken on how one interacts with the system once this function
157/// returns.
158///
159/// Because this requires a [`PanicInfo`] reference, this can only be called
160/// from a panic context.
161pub fn panic_print<PW: PanicWriter, C: Chip, PP: ProcessPrinter>(
162    writer_config: PW::Config,
163    panic_info: &PanicInfo,
164    nop: &dyn Fn(),
165    panic_resources: Option<&PanicResources<C, PP>>,
166) {
167    // Create the synchronous writer we can use to output the panic message.
168    let mut writer = PW::create_panic_writer(writer_config, panic_info);
169
170    panic_begin(nop);
171
172    // Flush debug buffer if needed
173    flush(&mut writer);
174
175    // Display general information about the kernel.
176    panic_banner(&mut writer, panic_info);
177
178    panic_resources.map(|pr| {
179        let chip = pr.chip.take();
180
181        // SAFETY: This may only be called during a panic, and we are guaranteed
182        // to be in a panic when running this function.
183        unsafe {
184            panic_cpu_state(chip, &mut writer);
185        }
186
187        chip.map(|c| {
188            use crate::platform::mpu::MPU;
189            // Some systems may enforce memory protection regions for the kernel,
190            // making application memory inaccessible. However, printing process
191            // information will attempt to access memory. If we are provided a chip
192            // reference, attempt to disable userspace memory protection first.
193            //
194            // SAFETY: This is safe because we are in a panic handler and we
195            // will never run processes again. We do not guarantee we will
196            // re-enable the MPU, but that is ok because in a panic we do not
197            // run processes.
198            unsafe { c.mpu().disable_app_mpu() }
199        });
200        pr.processes.take().map(|p| {
201            // SAFETY: We are guaranteed to be in a panic context.
202            unsafe {
203                panic_process_info(p, pr.printer.take(), &mut writer);
204            }
205        });
206    });
207}
208
209/// Tock default panic routine.
210///
211/// **NOTE:** The supplied `writer` must be synchronous.
212///
213/// This will print a detailed debugging message and then loop forever while
214/// blinking an LED in a recognizable pattern.
215///
216/// Because this requires a [`PanicInfo`] reference, this can only be called
217/// from a panic context.
218pub fn panic<L: hil::led::Led, PW: PanicWriter, C: Chip, PP: ProcessPrinter>(
219    leds: &mut [&L],
220    writer_config: PW::Config,
221    panic_info: &PanicInfo,
222    nop: &dyn Fn(),
223    panic_resources: Option<&PanicResources<C, PP>>,
224) -> ! {
225    // Call `panic_print` first which will print out the panic information and
226    // return
227    panic_print::<PW, C, PP>(writer_config, panic_info, nop, panic_resources);
228
229    // The system is no longer in a well-defined state, we cannot
230    // allow this function to return
231    //
232    // Forever blink LEDs in an infinite loop
233    panic_blink_forever(leds)
234}
235
236/// Tock panic routine, without the infinite LED-blinking loop.
237///
238/// This is useful for boards which do not feature LEDs to blink or want to
239/// implement their own behavior. This method returns after performing the panic
240/// dump.
241///
242/// After this method returns, the system is no longer in a well-defined state.
243/// Care must be taken on how one interacts with the system once this function
244/// returns.
245///
246/// **NOTE:** The supplied `writer` must be synchronous.
247///
248/// # Safety
249///
250/// - This must ONLY be called during a panic.
251pub unsafe fn panic_print_old<W: Write + IoWrite, C: Chip, PP: ProcessPrinter>(
252    writer: &mut W,
253    panic_info: &PanicInfo,
254    nop: &dyn Fn(),
255    panic_resources: Option<&PanicResources<C, PP>>,
256) {
257    // SAFETY: This has the same safety reasoning as `panic_print()`. This
258    // implementation is deprecated. When all callers are updated it will be
259    // removed.
260    unsafe {
261        panic_begin(nop);
262        // Flush debug buffer if needed
263        flush(writer);
264        panic_banner(writer, panic_info);
265
266        panic_resources.map(|pr| {
267            let chip = pr.chip.take();
268            panic_cpu_state(chip, writer);
269
270            chip.map(|c| {
271                // Some systems may enforce memory protection regions for the kernel,
272                // making application memory inaccessible. However, printing process
273                // information will attempt to access memory. If we are provided a chip
274                // reference, attempt to disable userspace memory protection first:
275                use crate::platform::mpu::MPU;
276                c.mpu().disable_app_mpu()
277            });
278            pr.processes.take().map(|p| {
279                panic_process_info(p, pr.printer.take(), writer);
280            });
281        });
282    }
283}
284
285/// Tock default panic routine.
286///
287/// **NOTE:** The supplied `writer` must be synchronous.
288///
289/// This will print a detailed debugging message and then loop forever while
290/// blinking an LED in a recognizable pattern.
291///
292/// # Safety
293///
294/// - This must ONLY be called during a panic.
295pub unsafe fn panic_old<L: hil::led::Led, W: Write + IoWrite, C: Chip, PP: ProcessPrinter>(
296    leds: &mut [&L],
297    writer: &mut W,
298    panic_info: &PanicInfo,
299    nop: &dyn Fn(),
300    panic_resources: Option<&PanicResources<C, PP>>,
301) -> ! {
302    // Call `panic_print` first which will print out the panic information and
303    // return.
304    //
305    // SAFETY: The requirements match this function.
306    unsafe {
307        panic_print_old(writer, panic_info, nop, panic_resources);
308    }
309
310    // The system is no longer in a well-defined state, we cannot
311    // allow this function to return
312    //
313    // Forever blink LEDs in an infinite loop
314    panic_blink_forever(leds)
315}
316
317/// Generic panic entry.
318///
319/// This opaque method should always be called at the beginning of a board's
320/// panic method to allow hooks for any core kernel cleanups that may be
321/// appropriate.
322pub fn panic_begin(nop: &dyn Fn()) {
323    // Let any outstanding uart DMA's finish
324    for _ in 0..200000 {
325        nop();
326    }
327}
328
329/// Lightweight prints about the current panic and kernel version.
330///
331/// **NOTE:** The supplied `writer` must be synchronous.
332///
333/// Because this requires a [`PanicInfo`] reference, this can only be called
334/// from a panic context.
335pub fn panic_banner<W: Write>(writer: &mut W, panic_info: &PanicInfo) {
336    // Expand `PanicInfo` manually rather than using its `Display`
337    // implementation. The `Display` implementation inserts bare LFs
338    // between the location line and the message body, rather than a
339    // CRLF.
340    if let Some(location) = panic_info.location() {
341        let _ = writer.write_fmt(format_args!(
342            "\r\npanicked at {}:{}:{}:\r\n{}\r\n",
343            location.file(),
344            location.line(),
345            location.column(),
346            panic_info.message(),
347        ));
348    } else {
349        let _ = writer.write_fmt(format_args!("\r\n{}\r\n", panic_info.message()));
350    }
351
352    // Print version of the kernel
353    if crate::KERNEL_PRERELEASE_VERSION != 0 {
354        let _ = writer.write_fmt(format_args!(
355            "\tKernel version {}.{}.{}-dev{}\r\n",
356            crate::KERNEL_MAJOR_VERSION,
357            crate::KERNEL_MINOR_VERSION,
358            crate::KERNEL_PATCH_VERSION,
359            crate::KERNEL_PRERELEASE_VERSION,
360        ));
361    } else {
362        let _ = writer.write_fmt(format_args!(
363            "\tKernel version {}.{}.{}\r\n",
364            crate::KERNEL_MAJOR_VERSION,
365            crate::KERNEL_MINOR_VERSION,
366            crate::KERNEL_PATCH_VERSION,
367        ));
368    }
369}
370
371/// Print current machine (CPU) state.
372///
373/// **NOTE:** The supplied `writer` must be synchronous.
374///
375/// # Safety
376///
377/// This may only be called during a panic.
378pub unsafe fn panic_cpu_state<W: Write, C: Chip>(chip: Option<&'static C>, writer: &mut W) {
379    // SAFETY: The function-level safety doc requires this only be called during
380    // a panic, matching the requirement for `print_state()`.
381    unsafe {
382        C::print_state(chip, writer);
383    }
384}
385
386/// More detailed prints about all processes.
387///
388/// **NOTE:** The supplied `writer` must be synchronous.
389///
390/// # Safety
391///
392/// This must only be called from a panic context.
393pub unsafe fn panic_process_info<PP: ProcessPrinter, W: Write>(
394    processes: &'static [ProcessSlot],
395    process_printer: Option<&'static PP>,
396    writer: &mut W,
397) {
398    process_printer.map(|printer| {
399        // print data about each process
400        let _ = writer.write_fmt(format_args!("\r\n---| App Status |---\r\n"));
401        for slot in processes {
402            slot.proc.get().map(|process| {
403                // Print the memory map and basic process info.
404                //
405                // Because we are using a synchronous printer we do not need to
406                // worry about looping on the print function.
407                printer.print_overview(process, &mut BinaryToWriteWrapper::new(writer), None);
408                // Print all of the process details.
409                process.print_full_process(writer);
410            });
411        }
412    });
413}
414
415/// Blinks a recognizable pattern forever.
416///
417/// The LED will blink "sporadically" in a somewhat irregular pattern. This
418/// should look different from a traditional blinking LED which typically blinks
419/// with a consistent duty cycle. The panic blinking sequence is intentionally
420/// unusual to make it easier to tell when a panic has occurred.
421///
422/// If a multi-color LED is used for the panic pattern, it is advised to turn
423/// off other LEDs before calling this method.
424///
425/// Generally, boards should blink red during panic if possible, otherwise
426/// choose the 'first' or most prominent LED. Some boards may find it
427/// appropriate to blink multiple LEDs (e.g. one on the top and one on the
428/// bottom), thus this method accepts an array, however most will only need one.
429pub fn panic_blink_forever<L: hil::led::Led>(leds: &mut [&L]) -> ! {
430    for led in leds.iter_mut() {
431        led.init();
432    }
433    loop {
434        for _ in 0..1000000 {
435            for led in leds.iter_mut() {
436                led.on();
437            }
438        }
439        for _ in 0..100000 {
440            for led in leds.iter_mut() {
441                led.off();
442            }
443        }
444        for _ in 0..1000000 {
445            for led in leds.iter_mut() {
446                led.on();
447            }
448        }
449        for _ in 0..500000 {
450            for led in leds.iter_mut() {
451                led.off();
452            }
453        }
454    }
455}
456
457// panic! support routines
458///////////////////////////////////////////////////////////////////
459
460///////////////////////////////////////////////////////////////////
461// debug_gpio! support
462
463/// Static variable that holds an array of debug GPIO references.
464pub static DEBUG_GPIOS: SingleThreadValue<MapCell<&'static [&'static dyn hil::gpio::Pin]>> =
465    SingleThreadValue::new();
466
467/// Initialize the static debug gpio variable.
468///
469/// This ensures it can safely be used as a global variable.
470#[cfg(target_has_atomic = "ptr")]
471pub fn initialize_debug_gpio<P: ThreadIdProvider>() {
472    DEBUG_GPIOS
473        .bind_to_thread::<P>(MapCell::empty())
474        .map_err(|_| ())
475        .unwrap();
476}
477
478/// Initialize the static debug gpio variable.
479///
480/// This ensures it can safely be used as a global variable.
481///
482/// # Safety
483///
484/// Callers of this function must ensure that this function is never called
485/// concurrently with other calls to [`initialize_debug_gpio_unsafe`].
486pub unsafe fn initialize_debug_gpio_unsafe<P: ThreadIdProvider>() {
487    unsafe {
488        DEBUG_GPIOS
489            .bind_to_thread_unsafe::<P>(MapCell::empty())
490            .map_err(|_| ())
491            .unwrap();
492    }
493}
494
495/// Map an array of GPIO pins to use for debugging.
496pub fn assign_gpios(gpio: &'static [&'static dyn hil::gpio::Pin]) {
497    DEBUG_GPIOS.get().map(|gpio_array_cell| {
498        gpio_array_cell.replace(gpio);
499    });
500}
501
502/// In-kernel gpio debugging that accepts any GPIO HIL method.
503#[macro_export]
504macro_rules! debug_gpio {
505    ($i:tt, $method:ident $(,)?) => {{
506        #[allow(unused_unsafe)]
507        unsafe {
508            $crate::debug::DEBUG_GPIOS.get().map(|debug_gpio_cell| {
509                debug_gpio_cell.map(|debug_gpio_array| {
510                    debug_gpio_array.get($i).map(|g| g.$method());
511                });
512            });
513        }
514    }};
515}
516
517///////////////////////////////////////////////////////////////////
518// debug! and debug_verbose! support
519
520/// A trait for writing debug output.
521///
522/// This can be used for example to implement asynchronous or synchronous
523/// writers, and buffered or unbuffered writers. Various platforms may have
524/// in-memory logs, memory mapped "endless" FIFOs, JTAG support for output,
525/// etc.
526pub trait DebugWriter {
527    /// Write bytes to output with overflow notification.
528    ///
529    /// The `overflow` slice is used as a message to be appended to the end of
530    /// the available buffer if it becomes full.
531    fn write(&self, bytes: &[u8], overflow_message: &[u8]) -> usize;
532
533    /// Available length of the internal buffer if limited.
534    ///
535    /// If the buffer can support a write of any size, it should lie and return
536    /// `usize::MAX`.
537    ///
538    /// Across subsequent calls to this function, without invoking `write()` in
539    /// between, this returned value may only increase, but never decrease.
540    fn available_len(&self) -> usize;
541
542    /// How many bytes are buffered and not yet written.
543    fn to_write_len(&self) -> usize;
544
545    /// Publish bytes from the internal buffer to the output.
546    ///
547    /// Returns how many bytes were written.
548    fn publish(&self) -> usize;
549
550    /// Flush any buffered bytes to the provided output writer.
551    ///
552    /// `flush()` should be used to write any buffered bytes to a new `writer`
553    /// instead of the internal writer that `publish()` would use.
554    fn flush(&self, writer: &mut dyn IoWrite);
555}
556
557/// Static variable that holds the kernel's reference to the debug tool.
558///
559/// This is needed so the `debug!()` macros have a reference to the object to
560/// use.
561static DEBUG_WRITER: SingleThreadValue<MapCell<&'static dyn DebugWriter>> =
562    SingleThreadValue::new();
563
564/// Static variable that holds how many times `debug!()` has been called.
565///
566/// This enables printing a verbose header message that enumerates independent
567/// debug messages.
568static DEBUG_WRITER_COUNT: SingleThreadValue<Cell<usize>> = SingleThreadValue::new();
569
570/// Initialize the static debug writer.
571///
572/// This ensures it can safely be used as a global variable.
573#[cfg(target_has_atomic = "ptr")]
574pub fn initialize_debug_writer_wrapper<P: ThreadIdProvider>() {
575    DEBUG_WRITER
576        .bind_to_thread::<P>(MapCell::empty())
577        .map_err(|_| ())
578        .unwrap();
579    DEBUG_WRITER_COUNT
580        .bind_to_thread::<P>(Cell::new(0))
581        .map_err(|_| ())
582        .unwrap();
583}
584
585/// Initialize the static debug writer.
586///
587/// This ensures it can safely be used as a global variable.
588///
589/// # Safety
590///
591/// Callers of this function must ensure that this function is never called
592/// concurrently with other calls to [`initialize_debug_writer_wrapper_unsafe`].
593pub unsafe fn initialize_debug_writer_wrapper_unsafe<P: ThreadIdProvider>() {
594    unsafe {
595        DEBUG_WRITER
596            .bind_to_thread_unsafe::<P>(MapCell::empty())
597            .map_err(|_| ())
598            .unwrap();
599        DEBUG_WRITER_COUNT
600            .bind_to_thread_unsafe::<P>(Cell::new(0))
601            .map_err(|_| ())
602            .unwrap();
603    }
604}
605
606fn try_get_debug_writer<F, R>(closure: F) -> Option<R>
607where
608    F: FnOnce(&dyn DebugWriter) -> R,
609{
610    DEBUG_WRITER
611        .get()
612        .and_then(|dw| dw.map_or(None, |writer| Some(closure(*writer))))
613}
614
615/// Function used by board main.rs to set a reference to the writer.
616pub fn set_debug_writer_wrapper<C: SetDebugWriterCapability>(
617    debug_writer: &'static dyn DebugWriter,
618    _cap: C,
619) {
620    DEBUG_WRITER.get().map(|dw| dw.replace(debug_writer));
621}
622
623impl Write for &dyn DebugWriter {
624    fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
625        self.write(s.as_bytes(), b"");
626        Ok(())
627    }
628}
629
630/// Write a debug message without a trailing newline.
631pub fn debug_print(args: Arguments) {
632    try_get_debug_writer(|mut writer| {
633        let _ = write(&mut writer, args);
634        writer.publish();
635    });
636}
637
638/// Write a debug message with a trailing newline.
639pub fn debug_println(args: Arguments) {
640    try_get_debug_writer(|mut writer| {
641        let _ = write(&mut writer, args);
642        let _ = writer.write_str("\r\n");
643        writer.publish();
644    });
645}
646
647/// Write a [`ReadableProcessSlice`] to the debug output.
648///
649/// # Errors
650///
651/// Will return `Err` if it is not possible to write any output.
652pub fn debug_slice(slice: &ReadableProcessSlice) -> Result<usize, ()> {
653    try_get_debug_writer(|writer| {
654        let mut total = 0;
655        for b in slice.iter() {
656            let buf: [u8; 1] = [b.get(); 1];
657            let count = writer.write(&buf, b"");
658            if count > 0 {
659                total += count;
660            } else {
661                break;
662            }
663        }
664        writer.publish();
665        total
666    })
667    .ok_or(())
668}
669
670/// Return how many bytes are remaining in the internal debug buffer.
671pub fn debug_available_len() -> usize {
672    try_get_debug_writer(|writer| writer.available_len()).unwrap_or(0)
673}
674
675fn write_header(
676    writer: &mut &dyn DebugWriter,
677    (file, line): &(&'static str, u32),
678) -> Result<(), core::fmt::Error> {
679    let count = DEBUG_WRITER_COUNT.get().map_or(0, |count| {
680        count.increment();
681        count.get()
682    });
683
684    writer.write_fmt(format_args!("TOCK_DEBUG({}): {}:{}: ", count, file, line))
685}
686
687/// Write a debug message with file and line information without a trailing
688/// newline.
689pub fn debug_verbose_print(args: Arguments, file_line: &(&'static str, u32)) {
690    try_get_debug_writer(|mut writer| {
691        let _ = write_header(&mut writer, file_line);
692        let _ = write(&mut writer, args);
693        writer.publish();
694    });
695}
696
697/// Write a debug message with file and line information with a trailing
698/// newline.
699pub fn debug_verbose_println(args: Arguments, file_line: &(&'static str, u32)) {
700    try_get_debug_writer(|mut writer| {
701        let _ = write_header(&mut writer, file_line);
702        let _ = write(&mut writer, args);
703        let _ = writer.write_str("\r\n");
704        writer.publish();
705    });
706}
707
708/// In-kernel `println()` debugging.
709#[macro_export]
710macro_rules! debug {
711    () => ({
712        // Allow an empty debug!() to print the location when hit
713        debug!("")
714    });
715    ($msg:expr $(,)?) => ({
716        $crate::debug::debug_println(format_args!($msg));
717    });
718    ($fmt:expr, $($arg:tt)+) => ({
719        $crate::debug::debug_println(format_args!($fmt, $($arg)+));
720    });
721}
722
723/// In-kernel `println()` debugging that can take a process slice.
724#[macro_export]
725macro_rules! debug_process_slice {
726    ($msg:expr $(,)?) => {{ $crate::debug::debug_slice($msg) }};
727}
728
729/// In-kernel `println()` debugging with filename and line numbers.
730#[macro_export]
731macro_rules! debug_verbose {
732    () => ({
733        // Allow an empty debug_verbose!() to print the location when hit
734        debug_verbose!("")
735    });
736    ($msg:expr $(,)?) => ({
737        $crate::debug::debug_verbose_println(format_args!($msg), {
738            // TODO: Maybe make opposite choice of panic!, no `static`, more
739            // runtime code for less static data
740            static _FILE_LINE: (&'static str, u32) = (file!(), line!());
741            &_FILE_LINE
742        })
743    });
744    ($fmt:expr, $($arg:tt)+) => ({
745        $crate::debug::debug_verbose_println(format_args!($fmt, $($arg)+), {
746            static _FILE_LINE: (&'static str, u32) = (file!(), line!());
747            &_FILE_LINE
748        })
749    });
750}
751
752/// Prints out the expression and its location, then returns it.
753///
754/// ```rust,ignore
755/// let foo: u8 = debug_expr!(0xff);
756/// // Prints [main.rs:2] 0xff = 255
757/// ```
758/// Taken straight from Rust `std::dbg`.
759#[macro_export]
760macro_rules! debug_expr {
761    // NOTE: We cannot use `concat!` to make a static string as a format
762    // argument of `eprintln!` because `file!` could contain a `{` or `$val`
763    // expression could be a block (`{ .. }`), in which case the `eprintln!`
764    // will be malformed.
765    () => {
766        $crate::debug!("[{}:{}]", file!(), line!())
767    };
768    ($val:expr $(,)?) => {
769        // Use of `match` here is intentional because it affects the lifetimes
770        // of temporaries - https://stackoverflow.com/a/48732525/1063961
771        match $val {
772            tmp => {
773                $crate::debug!("[{}:{}] {} = {:#?}",
774                    file!(), line!(), stringify!($val), &tmp);
775                tmp
776            }
777        }
778    };
779    ($($val:expr),+ $(,)?) => {
780        ($($crate::debug_expr!($val)),+,)
781    };
782}
783
784/// Flush any stored messages to the output writer.
785fn flush<W: Write + IoWrite>(writer: &mut W) {
786    try_get_debug_writer(|debug_writer|{
787        if debug_writer.to_write_len() > 0 {
788            let _ = writer.write_str(
789                    "\r\n---| Debug buffer not empty. Flushing. May repeat some of last message(s):\r\n",
790                );
791            debug_writer.flush(writer);
792        }
793    }).or_else(||{
794        let _ = writer.write_str(
795            "\r\n---| Global debug writer not registered.\
796             \r\n     Call `set_debug_writer_wrapper` in board initialization.\r\n",
797        );
798        None
799    });
800}