@@ -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,26 @@ 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
5256 /// Push a "frame" (actor exit) onto the backtrace.
57+ ///
58+ /// This should be called every time an actor exits.
5359 pub fn push_frame ( & mut self , frame : Frame ) {
5460 self . frames . push ( frame)
5561 }
@@ -83,9 +89,7 @@ impl Display for Frame {
8389 }
8490}
8591
86- /// The ultimate "cause" of a failed message.
87- #[ derive( Clone , Debug ) ]
88- pub struct Cause {
92+ struct SyscallCause {
8993 /// The syscall "module".
9094 pub module : & ' static str ,
9195 /// The syscall function name.
@@ -96,23 +100,45 @@ pub struct Cause {
96100 pub message : String ,
97101}
98102
103+ /// The ultimate "cause" of a failed message.
104+ #[ derive( Clone , Debug ) ]
105+ pub enum Cause {
106+ /// The original cause was a syscall error.
107+ Syscall ( SyscallCause ) ,
108+ /// The original cause was a fatal error.
109+ Fatal ( String ) ,
110+ }
111+
99112impl Cause {
100- pub fn new ( module : & ' static str , function : & ' static str , err : SyscallError ) -> Self {
101- Self {
113+ /// Records a failing syscall as the cause of a backtrace.
114+ pub fn from_syscall ( module : & ' static str , function : & ' static str , err : SyscallError ) -> Self {
115+ Self :: Syscall ( SyscallCause {
102116 module,
103117 function,
104118 error : err. 1 ,
105119 message : err. 0 ,
106- }
120+ } )
121+ }
122+
123+ /// Records a fatal error as the cause of a backtrace.
124+ pub fn from_fatal ( err : anyhow:: Error ) -> Self {
125+ Self :: Fatal ( err. into ( ) )
107126 }
108127}
109128
110129impl Display for Cause {
111130 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- )
131+ match self {
132+ Cause :: Syscall ( cause) => {
133+ write ! (
134+ f,
135+ "{}::{} -- {} ({}: {})" ,
136+ cause. module, cause. function, & cause. message, cause. error as u32 , cause. error,
137+ )
138+ }
139+ Cause :: Fatal ( msg) => {
140+ write ! ( f, "[FATAL] {}" , msg)
141+ }
142+ }
117143 }
118144}
0 commit comments