@@ -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 }
@@ -83,9 +98,8 @@ impl Display for Frame {
8398 }
8499}
85100
86- /// The ultimate "cause" of a failed message.
87101#[ derive( Clone , Debug ) ]
88- pub struct Cause {
102+ pub struct SyscallCause {
89103 /// The syscall "module".
90104 pub module : & ' static str ,
91105 /// The syscall function name.
@@ -96,23 +110,64 @@ pub struct Cause {
96110 pub message : String ,
97111}
98112
113+ #[ derive( Clone , Debug ) ]
114+ pub struct FatalCause {
115+ /// The error message from the error.
116+ pub error_msg : String ,
117+ /// The original cause that initiated the error chain.
118+ pub root_cause : 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+ pub backtrace : String ,
122+ }
123+
124+ /// The ultimate "cause" of a failed message.
125+ #[ derive( Clone , Debug ) ]
126+ pub enum Cause {
127+ /// The original cause was a syscall error.
128+ Syscall ( SyscallCause ) ,
129+ /// The original cause was a fatal error.
130+ Fatal ( FatalCause ) ,
131+ }
132+
99133impl Cause {
100- pub fn new ( module : & ' static str , function : & ' static str , err : SyscallError ) -> Self {
101- Self {
134+ /// Records a failing syscall as the cause of a backtrace.
135+ pub fn from_syscall ( module : & ' static str , function : & ' static str , err : SyscallError ) -> Self {
136+ Self :: Syscall ( SyscallCause {
102137 module,
103138 function,
104139 error : err. 1 ,
105140 message : err. 0 ,
106- }
141+ } )
142+ }
143+
144+ /// Records a fatal error as the cause of a backtrace.
145+ pub fn from_fatal ( err : anyhow:: Error ) -> Self {
146+ Self :: Fatal ( FatalCause {
147+ error_msg : err. to_string ( ) ,
148+ root_cause : err. root_cause ( ) . to_string ( ) ,
149+ backtrace : err. backtrace ( ) . to_string ( ) ,
150+ } )
107151 }
108152}
109153
110154impl Display for Cause {
111155 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- )
156+ match self {
157+ Cause :: Syscall ( cause) => {
158+ write ! (
159+ f,
160+ "{}::{} -- {} ({}: {})" ,
161+ cause. module, cause. function, & cause. message, cause. error as u32 , cause. error,
162+ )
163+ }
164+ Cause :: Fatal ( msg) => {
165+ write ! (
166+ f,
167+ "[FATAL] Root cause: {}, Stacktrace: {}" ,
168+ msg. root_cause, msg. backtrace
169+ )
170+ }
171+ }
117172 }
118173}
0 commit comments