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/// **NOTE:** The supplied `writer` must be synchronous.
160pub unsafe fn panic_print<PW: PanicWriter, C: Chip, PP: ProcessPrinter>(
161    writer_config: PW::Config,
162    panic_info: &PanicInfo,
163    nop: &dyn Fn(),
164    panic_resources: Option<&PanicResources<C, PP>>,
165) {
166    unsafe {
167        // Create the synchronous writer we can use to output the panic message.
168        let mut writer = PW::create_panic_writer(writer_config);
169
170        panic_begin(nop);
171        // Flush debug buffer if needed
172        flush(&mut writer);
173        panic_banner(&mut writer, panic_info);
174
175        panic_resources.map(|pr| {
176            let chip = pr.chip.take();
177            panic_cpu_state(chip, &mut writer);
178
179            chip.map(|c| {
180                // Some systems may enforce memory protection regions for the kernel,
181                // making application memory inaccessible. However, printing process
182                // information will attempt to access memory. If we are provided a chip
183                // reference, attempt to disable userspace memory protection first:
184                use crate::platform::mpu::MPU;
185                c.mpu().disable_app_mpu()
186            });
187            pr.processes.take().map(|p| {
188                panic_process_info(p, pr.printer.take(), &mut writer);
189            });
190        });
191    }
192}
193
194/// Tock default panic routine.
195///
196/// **NOTE:** The supplied `writer` must be synchronous.
197///
198/// This will print a detailed debugging message and then loop forever while
199/// blinking an LED in a recognizable pattern.
200pub unsafe fn panic<L: hil::led::Led, PW: PanicWriter, C: Chip, PP: ProcessPrinter>(
201    leds: &mut [&L],
202    writer_config: PW::Config,
203    panic_info: &PanicInfo,
204    nop: &dyn Fn(),
205    panic_resources: Option<&PanicResources<C, PP>>,
206) -> ! {
207    unsafe {
208        // Call `panic_print` first which will print out the panic information and
209        // return
210        panic_print::<PW, C, PP>(writer_config, panic_info, nop, panic_resources);
211
212        // The system is no longer in a well-defined state, we cannot
213        // allow this function to return
214        //
215        // Forever blink LEDs in an infinite loop
216        panic_blink_forever(leds)
217    }
218}
219
220/// Tock panic routine, without the infinite LED-blinking loop.
221///
222/// This is useful for boards which do not feature LEDs to blink or want to
223/// implement their own behavior. This method returns after performing the panic
224/// dump.
225///
226/// After this method returns, the system is no longer in a well-defined state.
227/// Care must be taken on how one interacts with the system once this function
228/// returns.
229///
230/// **NOTE:** The supplied `writer` must be synchronous.
231pub unsafe fn panic_print_old<W: Write + IoWrite, C: Chip, PP: ProcessPrinter>(
232    writer: &mut W,
233    panic_info: &PanicInfo,
234    nop: &dyn Fn(),
235    panic_resources: Option<&PanicResources<C, PP>>,
236) {
237    unsafe {
238        panic_begin(nop);
239        // Flush debug buffer if needed
240        flush(writer);
241        panic_banner(writer, panic_info);
242
243        panic_resources.map(|pr| {
244            let chip = pr.chip.take();
245            panic_cpu_state(chip, writer);
246
247            chip.map(|c| {
248                // Some systems may enforce memory protection regions for the kernel,
249                // making application memory inaccessible. However, printing process
250                // information will attempt to access memory. If we are provided a chip
251                // reference, attempt to disable userspace memory protection first:
252                use crate::platform::mpu::MPU;
253                c.mpu().disable_app_mpu()
254            });
255            pr.processes.take().map(|p| {
256                panic_process_info(p, pr.printer.take(), writer);
257            });
258        });
259    }
260}
261
262/// Tock default panic routine.
263///
264/// **NOTE:** The supplied `writer` must be synchronous.
265///
266/// This will print a detailed debugging message and then loop forever while
267/// blinking an LED in a recognizable pattern.
268pub unsafe fn panic_old<L: hil::led::Led, W: Write + IoWrite, C: Chip, PP: ProcessPrinter>(
269    leds: &mut [&L],
270    writer: &mut W,
271    panic_info: &PanicInfo,
272    nop: &dyn Fn(),
273    panic_resources: Option<&PanicResources<C, PP>>,
274) -> ! {
275    unsafe {
276        // Call `panic_print` first which will print out the panic information and
277        // return
278        panic_print_old(writer, panic_info, nop, panic_resources);
279
280        // The system is no longer in a well-defined state, we cannot
281        // allow this function to return
282        //
283        // Forever blink LEDs in an infinite loop
284        panic_blink_forever(leds)
285    }
286}
287
288/// Generic panic entry.
289///
290/// This opaque method should always be called at the beginning of a board's
291/// panic method to allow hooks for any core kernel cleanups that may be
292/// appropriate.
293pub unsafe fn panic_begin(nop: &dyn Fn()) {
294    // Let any outstanding uart DMA's finish
295    for _ in 0..200000 {
296        nop();
297    }
298}
299
300/// Lightweight prints about the current panic and kernel version.
301///
302/// **NOTE:** The supplied `writer` must be synchronous.
303pub unsafe fn panic_banner<W: Write>(writer: &mut W, panic_info: &PanicInfo) {
304    // Expand `PanicInfo` manually rather than using its `Display`
305    // implementation. The `Display` implementation inserts bare LFs
306    // between the location line and the message body, rather than a
307    // CRLF.
308    if let Some(location) = panic_info.location() {
309        let _ = writer.write_fmt(format_args!(
310            "\r\npanicked at {}:{}:{}:\r\n{}\r\n",
311            location.file(),
312            location.line(),
313            location.column(),
314            panic_info.message(),
315        ));
316    } else {
317        let _ = writer.write_fmt(format_args!("\r\n{}\r\n", panic_info.message()));
318    }
319
320    // Print version of the kernel
321    if crate::KERNEL_PRERELEASE_VERSION != 0 {
322        let _ = writer.write_fmt(format_args!(
323            "\tKernel version {}.{}.{}-dev{}\r\n",
324            crate::KERNEL_MAJOR_VERSION,
325            crate::KERNEL_MINOR_VERSION,
326            crate::KERNEL_PATCH_VERSION,
327            crate::KERNEL_PRERELEASE_VERSION,
328        ));
329    } else {
330        let _ = writer.write_fmt(format_args!(
331            "\tKernel version {}.{}.{}\r\n",
332            crate::KERNEL_MAJOR_VERSION,
333            crate::KERNEL_MINOR_VERSION,
334            crate::KERNEL_PATCH_VERSION,
335        ));
336    }
337}
338
339/// Print current machine (CPU) state.
340///
341/// **NOTE:** The supplied `writer` must be synchronous.
342pub unsafe fn panic_cpu_state<W: Write, C: Chip>(chip: Option<&'static C>, writer: &mut W) {
343    unsafe {
344        C::print_state(chip, writer);
345    }
346}
347
348/// More detailed prints about all processes.
349///
350/// **NOTE:** The supplied `writer` must be synchronous.
351pub unsafe fn panic_process_info<PP: ProcessPrinter, W: Write>(
352    processes: &'static [ProcessSlot],
353    process_printer: Option<&'static PP>,
354    writer: &mut W,
355) {
356    process_printer.map(|printer| {
357        // print data about each process
358        let _ = writer.write_fmt(format_args!("\r\n---| App Status |---\r\n"));
359        for slot in processes {
360            slot.proc.get().map(|process| {
361                // Print the memory map and basic process info.
362                //
363                // Because we are using a synchronous printer we do not need to
364                // worry about looping on the print function.
365                printer.print_overview(process, &mut BinaryToWriteWrapper::new(writer), None);
366                // Print all of the process details.
367                process.print_full_process(writer);
368            });
369        }
370    });
371}
372
373/// Blinks a recognizable pattern forever.
374///
375/// The LED will blink "sporadically" in a somewhat irregular pattern. This
376/// should look different from a traditional blinking LED which typically blinks
377/// with a consistent duty cycle. The panic blinking sequence is intentionally
378/// unusual to make it easier to tell when a panic has occurred.
379///
380/// If a multi-color LED is used for the panic pattern, it is advised to turn
381/// off other LEDs before calling this method.
382///
383/// Generally, boards should blink red during panic if possible, otherwise
384/// choose the 'first' or most prominent LED. Some boards may find it
385/// appropriate to blink multiple LEDs (e.g. one on the top and one on the
386/// bottom), thus this method accepts an array, however most will only need one.
387pub fn panic_blink_forever<L: hil::led::Led>(leds: &mut [&L]) -> ! {
388    for led in leds.iter_mut() {
389        led.init();
390    }
391    loop {
392        for _ in 0..1000000 {
393            for led in leds.iter_mut() {
394                led.on();
395            }
396        }
397        for _ in 0..100000 {
398            for led in leds.iter_mut() {
399                led.off();
400            }
401        }
402        for _ in 0..1000000 {
403            for led in leds.iter_mut() {
404                led.on();
405            }
406        }
407        for _ in 0..500000 {
408            for led in leds.iter_mut() {
409                led.off();
410            }
411        }
412    }
413}
414
415// panic! support routines
416///////////////////////////////////////////////////////////////////
417
418///////////////////////////////////////////////////////////////////
419// debug_gpio! support
420
421/// Static variable that holds an array of debug GPIO references.
422pub static DEBUG_GPIOS: SingleThreadValue<MapCell<&'static [&'static dyn hil::gpio::Pin]>> =
423    SingleThreadValue::new();
424
425/// Initialize the static debug gpio variable.
426///
427/// This ensures it can safely be used as a global variable.
428#[cfg(target_has_atomic = "ptr")]
429pub fn initialize_debug_gpio<P: ThreadIdProvider>() {
430    DEBUG_GPIOS
431        .bind_to_thread::<P>(MapCell::empty())
432        .map_err(|_| ())
433        .unwrap();
434}
435
436/// Initialize the static debug gpio variable.
437///
438/// This ensures it can safely be used as a global variable.
439///
440/// # Safety
441///
442/// Callers of this function must ensure that this function is never called
443/// concurrently with other calls to [`initialize_debug_gpio_unsafe`].
444pub unsafe fn initialize_debug_gpio_unsafe<P: ThreadIdProvider>() {
445    unsafe {
446        DEBUG_GPIOS
447            .bind_to_thread_unsafe::<P>(MapCell::empty())
448            .map_err(|_| ())
449            .unwrap();
450    }
451}
452
453/// Map an array of GPIO pins to use for debugging.
454pub fn assign_gpios(gpio: &'static [&'static dyn hil::gpio::Pin]) {
455    DEBUG_GPIOS.get().map(|gpio_array_cell| {
456        gpio_array_cell.replace(gpio);
457    });
458}
459
460/// In-kernel gpio debugging that accepts any GPIO HIL method.
461#[macro_export]
462macro_rules! debug_gpio {
463    ($i:tt, $method:ident $(,)?) => {{
464        #[allow(unused_unsafe)]
465        unsafe {
466            $crate::debug::DEBUG_GPIOS.get().map(|debug_gpio_cell| {
467                debug_gpio_cell.map(|debug_gpio_array| {
468                    debug_gpio_array.get($i).map(|g| g.$method());
469                });
470            });
471        }
472    }};
473}
474
475///////////////////////////////////////////////////////////////////
476// debug! and debug_verbose! support
477
478/// A trait for writing debug output.
479///
480/// This can be used for example to implement asynchronous or synchronous
481/// writers, and buffered or unbuffered writers. Various platforms may have
482/// in-memory logs, memory mapped "endless" FIFOs, JTAG support for output,
483/// etc.
484pub trait DebugWriter {
485    /// Write bytes to output with overflow notification.
486    ///
487    /// The `overflow` slice is used as a message to be appended to the end of
488    /// the available buffer if it becomes full.
489    fn write(&self, bytes: &[u8], overflow_message: &[u8]) -> usize;
490
491    /// Available length of the internal buffer if limited.
492    ///
493    /// If the buffer can support a write of any size, it should lie and return
494    /// `usize::MAX`.
495    ///
496    /// Across subsequent calls to this function, without invoking `write()` in
497    /// between, this returned value may only increase, but never decrease.
498    fn available_len(&self) -> usize;
499
500    /// How many bytes are buffered and not yet written.
501    fn to_write_len(&self) -> usize;
502
503    /// Publish bytes from the internal buffer to the output.
504    ///
505    /// Returns how many bytes were written.
506    fn publish(&self) -> usize;
507
508    /// Flush any buffered bytes to the provided output writer.
509    ///
510    /// `flush()` should be used to write any buffered bytes to a new `writer`
511    /// instead of the internal writer that `publish()` would use.
512    fn flush(&self, writer: &mut dyn IoWrite);
513}
514
515/// Static variable that holds the kernel's reference to the debug tool.
516///
517/// This is needed so the `debug!()` macros have a reference to the object to
518/// use.
519static DEBUG_WRITER: SingleThreadValue<MapCell<&'static dyn DebugWriter>> =
520    SingleThreadValue::new();
521
522/// Static variable that holds how many times `debug!()` has been called.
523///
524/// This enables printing a verbose header message that enumerates independent
525/// debug messages.
526static DEBUG_WRITER_COUNT: SingleThreadValue<Cell<usize>> = SingleThreadValue::new();
527
528/// Initialize the static debug writer.
529///
530/// This ensures it can safely be used as a global variable.
531#[cfg(target_has_atomic = "ptr")]
532pub fn initialize_debug_writer_wrapper<P: ThreadIdProvider>() {
533    DEBUG_WRITER
534        .bind_to_thread::<P>(MapCell::empty())
535        .map_err(|_| ())
536        .unwrap();
537    DEBUG_WRITER_COUNT
538        .bind_to_thread::<P>(Cell::new(0))
539        .map_err(|_| ())
540        .unwrap();
541}
542
543/// Initialize the static debug writer.
544///
545/// This ensures it can safely be used as a global variable.
546///
547/// # Safety
548///
549/// Callers of this function must ensure that this function is never called
550/// concurrently with other calls to [`initialize_debug_writer_wrapper_unsafe`].
551pub unsafe fn initialize_debug_writer_wrapper_unsafe<P: ThreadIdProvider>() {
552    unsafe {
553        DEBUG_WRITER
554            .bind_to_thread_unsafe::<P>(MapCell::empty())
555            .map_err(|_| ())
556            .unwrap();
557        DEBUG_WRITER_COUNT
558            .bind_to_thread_unsafe::<P>(Cell::new(0))
559            .map_err(|_| ())
560            .unwrap();
561    }
562}
563
564fn try_get_debug_writer<F, R>(closure: F) -> Option<R>
565where
566    F: FnOnce(&dyn DebugWriter) -> R,
567{
568    DEBUG_WRITER
569        .get()
570        .and_then(|dw| dw.map_or(None, |writer| Some(closure(*writer))))
571}
572
573/// Function used by board main.rs to set a reference to the writer.
574pub fn set_debug_writer_wrapper<C: SetDebugWriterCapability>(
575    debug_writer: &'static dyn DebugWriter,
576    _cap: C,
577) {
578    DEBUG_WRITER.get().map(|dw| dw.replace(debug_writer));
579}
580
581impl Write for &dyn DebugWriter {
582    fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
583        self.write(s.as_bytes(), b"");
584        Ok(())
585    }
586}
587
588/// Write a debug message without a trailing newline.
589pub fn debug_print(args: Arguments) {
590    try_get_debug_writer(|mut writer| {
591        let _ = write(&mut writer, args);
592        writer.publish();
593    });
594}
595
596/// Write a debug message with a trailing newline.
597pub fn debug_println(args: Arguments) {
598    try_get_debug_writer(|mut writer| {
599        let _ = write(&mut writer, args);
600        let _ = writer.write_str("\r\n");
601        writer.publish();
602    });
603}
604
605/// Write a [`ReadableProcessSlice`] to the debug output.
606///
607/// # Errors
608///
609/// Will return `Err` if it is not possible to write any output.
610pub fn debug_slice(slice: &ReadableProcessSlice) -> Result<usize, ()> {
611    try_get_debug_writer(|writer| {
612        let mut total = 0;
613        for b in slice.iter() {
614            let buf: [u8; 1] = [b.get(); 1];
615            let count = writer.write(&buf, b"");
616            if count > 0 {
617                total += count;
618            } else {
619                break;
620            }
621        }
622        writer.publish();
623        total
624    })
625    .ok_or(())
626}
627
628/// Return how many bytes are remaining in the internal debug buffer.
629pub fn debug_available_len() -> usize {
630    try_get_debug_writer(|writer| writer.available_len()).unwrap_or(0)
631}
632
633fn write_header(
634    writer: &mut &dyn DebugWriter,
635    (file, line): &(&'static str, u32),
636) -> Result<(), core::fmt::Error> {
637    let count = DEBUG_WRITER_COUNT.get().map_or(0, |count| {
638        count.increment();
639        count.get()
640    });
641
642    writer.write_fmt(format_args!("TOCK_DEBUG({}): {}:{}: ", count, file, line))
643}
644
645/// Write a debug message with file and line information without a trailing
646/// newline.
647pub fn debug_verbose_print(args: Arguments, file_line: &(&'static str, u32)) {
648    try_get_debug_writer(|mut writer| {
649        let _ = write_header(&mut writer, file_line);
650        let _ = write(&mut writer, args);
651        writer.publish();
652    });
653}
654
655/// Write a debug message with file and line information with a trailing
656/// newline.
657pub fn debug_verbose_println(args: Arguments, file_line: &(&'static str, u32)) {
658    try_get_debug_writer(|mut writer| {
659        let _ = write_header(&mut writer, file_line);
660        let _ = write(&mut writer, args);
661        let _ = writer.write_str("\r\n");
662        writer.publish();
663    });
664}
665
666/// In-kernel `println()` debugging.
667#[macro_export]
668macro_rules! debug {
669    () => ({
670        // Allow an empty debug!() to print the location when hit
671        debug!("")
672    });
673    ($msg:expr $(,)?) => ({
674        $crate::debug::debug_println(format_args!($msg));
675    });
676    ($fmt:expr, $($arg:tt)+) => ({
677        $crate::debug::debug_println(format_args!($fmt, $($arg)+));
678    });
679}
680
681/// In-kernel `println()` debugging that can take a process slice.
682#[macro_export]
683macro_rules! debug_process_slice {
684    ($msg:expr $(,)?) => {{ $crate::debug::debug_slice($msg) }};
685}
686
687/// In-kernel `println()` debugging with filename and line numbers.
688#[macro_export]
689macro_rules! debug_verbose {
690    () => ({
691        // Allow an empty debug_verbose!() to print the location when hit
692        debug_verbose!("")
693    });
694    ($msg:expr $(,)?) => ({
695        $crate::debug::debug_verbose_println(format_args!($msg), {
696            // TODO: Maybe make opposite choice of panic!, no `static`, more
697            // runtime code for less static data
698            static _FILE_LINE: (&'static str, u32) = (file!(), line!());
699            &_FILE_LINE
700        })
701    });
702    ($fmt:expr, $($arg:tt)+) => ({
703        $crate::debug::debug_verbose_println(format_args!($fmt, $($arg)+), {
704            static _FILE_LINE: (&'static str, u32) = (file!(), line!());
705            &_FILE_LINE
706        })
707    });
708}
709
710/// Prints out the expression and its location, then returns it.
711///
712/// ```rust,ignore
713/// let foo: u8 = debug_expr!(0xff);
714/// // Prints [main.rs:2] 0xff = 255
715/// ```
716/// Taken straight from Rust `std::dbg`.
717#[macro_export]
718macro_rules! debug_expr {
719    // NOTE: We cannot use `concat!` to make a static string as a format
720    // argument of `eprintln!` because `file!` could contain a `{` or `$val`
721    // expression could be a block (`{ .. }`), in which case the `eprintln!`
722    // will be malformed.
723    () => {
724        $crate::debug!("[{}:{}]", file!(), line!())
725    };
726    ($val:expr $(,)?) => {
727        // Use of `match` here is intentional because it affects the lifetimes
728        // of temporaries - https://stackoverflow.com/a/48732525/1063961
729        match $val {
730            tmp => {
731                $crate::debug!("[{}:{}] {} = {:#?}",
732                    file!(), line!(), stringify!($val), &tmp);
733                tmp
734            }
735        }
736    };
737    ($($val:expr),+ $(,)?) => {
738        ($($crate::debug_expr!($val)),+,)
739    };
740}
741
742/// Flush any stored messages to the output writer.
743fn flush<W: Write + IoWrite>(writer: &mut W) {
744    try_get_debug_writer(|debug_writer|{
745        if debug_writer.to_write_len() > 0 {
746            let _ = writer.write_str(
747                    "\r\n---| Debug buffer not empty. Flushing. May repeat some of last message(s):\r\n",
748                );
749            debug_writer.flush(writer);
750        }
751    }).or_else(||{
752        let _ = writer.write_str(
753            "\r\n---| Global debug writer not registered.\
754             \r\n     Call `set_debug_writer_wrapper` in board initialization.\r\n",
755        );
756        None
757    });
758}