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