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}