riscv_semihosting/
debug.rs

1//! Interacting with debugging agent
2//!
3//! # Example
4//!
5//! This example will show how to terminate the QEMU session. The program
6//! should be running under QEMU with semihosting enabled
7//! (use `-semihosting` flag).
8//!
9//! Target program:
10//!
11//! ```no_run
12//! use riscv_semihosting::debug::{self, EXIT_SUCCESS, EXIT_FAILURE};
13//!
14//! if 2 == 2 {
15//!     // report success
16//!     debug::exit(EXIT_SUCCESS);
17//! } else {
18//!     // report failure
19//!     debug::exit(EXIT_FAILURE);
20//! }
21//!```
22
23/// This values are taken from section 5.5.2 of
24/// ADS Debug Target Guide (DUI0058).
25// TODO document
26#[allow(missing_docs)]
27pub enum Exception {
28    // Hardware reason codes
29    BranchThroughZero = 0x20000,
30    UndefinedInstr = 0x20001,
31    SoftwareInterrupt = 0x20002,
32    PrefetchAbort = 0x20003,
33    DataAbort = 0x20004,
34    AddressException = 0x20005,
35    IRQ = 0x20006,
36    FIQ = 0x20007,
37    // Software reason codes
38    BreakPoint = 0x20020,
39    WatchPoint = 0x20021,
40    StepComplete = 0x20022,
41    RunTimeErrorUnknown = 0x20023,
42    InternalError = 0x20024,
43    UserInterruption = 0x20025,
44    ApplicationExit = 0x20026,
45    StackOverflow = 0x20027,
46    DivisionByZero = 0x20028,
47    OSSpecific = 0x20029,
48}
49
50/// Status enum for `exit` syscall.
51pub type ExitStatus = Result<(), ()>;
52
53/// Successful execution of a program.
54pub const EXIT_SUCCESS: ExitStatus = Ok(());
55
56/// Unsuccessful execution of a program.
57pub const EXIT_FAILURE: ExitStatus = Err(());
58
59/// Reports to the debugger that the execution has completed.
60///
61/// This call can be used to terminate QEMU session and report back success
62/// or failure. If you need to pass more than one type of error, consider
63/// using `report_exception` syscall instead.
64///
65/// This call should not return. However, it is possible for the debugger
66/// to request that the application continue. In that case this call
67/// returns normally.
68///
69pub fn exit(status: ExitStatus) {
70    match status {
71        EXIT_SUCCESS => report_exception(Exception::ApplicationExit),
72        EXIT_FAILURE => report_exception(Exception::RunTimeErrorUnknown),
73    }
74}
75
76/// Report an exception to the debugger directly.
77///
78/// Exception handlers can use this SWI at the end of handler chains
79/// as the default action, to indicate that the exception has not been handled.
80///
81/// This call should not return. However, it is possible for the debugger
82/// to request that the application continue. In that case this call
83/// returns normally.
84///
85/// # Arguments
86///
87/// * `reason` - A reason code reported back to the debugger.
88///
89pub fn report_exception(reason: Exception) {
90    let code = reason as usize;
91    unsafe {
92        #[cfg(target_arch = "riscv64")]
93        syscall!(REPORT_EXCEPTION, code, 0);
94
95        #[cfg(not(target_arch = "riscv64"))]
96        syscall1!(REPORT_EXCEPTION, code);
97    }
98}