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}