@@ -7,7 +7,9 @@ use fvm_shared::{ActorID, MethodNum};
77
88use crate :: kernel:: SyscallError ;
99
10- /// A call backtrace records _why_ an actor exited with a specific error code.
10+ /// A call backtrace records the actors an error was propagated through, from
11+ /// the moment it was emitted. The original error is the _cause_. Backtraces are
12+ /// useful for identifying the root cause of an error.
1113#[ derive( Debug , Default , Clone ) ]
1214pub struct Backtrace {
1315 /// The actors through which this error was propagated from bottom (source) to top.
@@ -34,22 +36,35 @@ impl Backtrace {
3436 self . frames . is_empty ( ) && self . cause . is_none ( )
3537 }
3638
37- /// Clear the backtrace. This should be called:
38- ///
39- /// 1. Before all syscalls except "abort"
40- /// 2. After an actor returns with a 0 exit code.
39+ /// Clear the backtrace.
4140 pub fn clear ( & mut self ) {
4241 self . cause = None ;
4342 self . frames . clear ( ) ;
4443 }
4544
46- /// Set the backtrace cause. If there is an existing backtrace, this will clear it.
47- pub fn set_cause ( & mut self , cause : Cause ) {
45+ /// Begins a new backtrace. If there is an existing backtrace, this will clear it.
46+ ///
47+ /// Note: Backtraces are populated _backwards_. That is, a frame is inserted
48+ /// every time an actor returns. That's why `begin()` resets any currently
49+ /// accumulated state, as once an error occurs, we want to track its
50+ /// propagation all the way up.
51+ pub fn begin ( & mut self , cause : Cause ) {
4852 self . cause = Some ( cause) ;
4953 self . frames . clear ( ) ;
5054 }
5155
56+ /// Sets the cause of a backtrace.
57+ ///
58+ /// This is useful to stamp a backtrace with its cause after the frames
59+ /// have been collected, such as when we ultimately handle a fatal error at
60+ /// the top of its propagation chain.
61+ pub fn set_cause ( & mut self , cause : Cause ) {
62+ self . cause = Some ( cause) ;
63+ }
64+
5265 /// Push a "frame" (actor exit) onto the backtrace.
66+ ///
67+ /// This should be called every time an actor exits.
5368 pub fn push_frame ( & mut self , frame : Frame ) {
5469 self . frames . push ( frame)
5570 }
@@ -85,34 +100,69 @@ impl Display for Frame {
85100
86101/// The ultimate "cause" of a failed message.
87102#[ derive( Clone , Debug ) ]
88- pub struct Cause {
89- /// The syscall "module".
90- pub module : & ' static str ,
91- /// The syscall function name.
92- pub function : & ' static str ,
93- /// The exact syscall error.
94- pub error : ErrorNumber ,
95- /// The informational syscall message.
96- pub message : String ,
103+ pub enum Cause {
104+ /// The original cause was a syscall error.
105+ Syscall {
106+ /// The syscall "module".
107+ module : & ' static str ,
108+ /// The syscall function name.
109+ function : & ' static str ,
110+ /// The exact syscall error.
111+ error : ErrorNumber ,
112+ /// The informational syscall message.
113+ message : String ,
114+ } ,
115+ /// The original cause was a fatal error.
116+ Fatal {
117+ /// The alternate-formatted message from the anyhow error.
118+ error_msg : String ,
119+ /// The backtrace, captured if the relevant
120+ /// [environment variables](https://doc.rust-lang.org/std/backtrace/index.html#environment-variables) are enabled.
121+ backtrace : String ,
122+ } ,
97123}
98124
99125impl Cause {
100- pub fn new ( module : & ' static str , function : & ' static str , err : SyscallError ) -> Self {
101- Self {
126+ /// Records a failing syscall as the cause of a backtrace.
127+ pub fn from_syscall ( module : & ' static str , function : & ' static str , err : SyscallError ) -> Self {
128+ Self :: Syscall {
102129 module,
103130 function,
104131 error : err. 1 ,
105132 message : err. 0 ,
106133 }
107134 }
135+
136+ /// Records a fatal error as the cause of a backtrace.
137+ pub fn from_fatal ( err : anyhow:: Error ) -> Self {
138+ Self :: Fatal {
139+ error_msg : format ! ( "{:#}" , err) ,
140+ backtrace : err. backtrace ( ) . to_string ( ) ,
141+ }
142+ }
108143}
109144
110145impl Display for Cause {
111146 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
112- write ! (
113- f,
114- "{}::{} -- {} ({}: {})" ,
115- self . module, self . function, & self . message, self . error as u32 , self . error,
116- )
147+ match self {
148+ Cause :: Syscall {
149+ module,
150+ function,
151+ error,
152+ message,
153+ } => {
154+ write ! (
155+ f,
156+ "{}::{} -- {} ({}: {})" ,
157+ module, function, & message, * error as u32 , error,
158+ )
159+ }
160+ Cause :: Fatal {
161+ error_msg,
162+ backtrace,
163+ } => {
164+ write ! ( f, "[FATAL] Error: {}, Backtrace:\n {}" , error_msg, backtrace)
165+ }
166+ }
117167 }
118168}
0 commit comments