cyfs_debug/panic/
panic.rs

1use panic::PanicInfo;
2
3use backtrace::{Backtrace, BacktraceFrame};
4use sha2::Digest;
5use std::panic;
6use std::thread;
7use serde::{Serialize, Deserialize};
8
9#[derive(Clone, Debug, Serialize, Deserialize)]
10pub struct CyfsPanicInfo {
11    pub msg: String,
12    pub msg_with_symbol: String,
13    pub hash: String,
14}
15
16impl CyfsPanicInfo {
17    pub fn new(backtrace: Backtrace, info: &PanicInfo) -> Self {
18        let backtrace_msg = Self::format_backtrace(&backtrace);
19        let msg = Self::format_info(info, &backtrace_msg);
20
21        let backtrace_msg = Self::format_backtrace_with_symbol(&backtrace);
22        let msg_with_symbol = Self::format_info(info, &backtrace_msg);
23
24        let hash = Self::calc_hash(&backtrace);
25        let ret = Self {
26            msg,
27            msg_with_symbol,
28            hash,
29        };
30
31        warn!("{}", ret.msg);
32        warn!("{}", ret.msg_with_symbol);
33        ret
34    }
35
36    fn format_info(info: &PanicInfo, backtrace: &str) -> String {
37        let thread = thread::current();
38        let thread = thread.name().unwrap_or("unnamed");
39
40        let msg = match info.payload().downcast_ref::<&'static str>() {
41            Some(s) => *s,
42            None => match info.payload().downcast_ref::<String>() {
43                Some(s) => &**s,
44                None => "Box<Any>",
45            },
46        };
47
48        let msg = match info.location() {
49            Some(location) => {
50                format!(
51                    "thread '{}' panicked at '{}': {}:{}\n{}",
52                    thread,
53                    msg,
54                    location.file(),
55                    location.line(),
56                    backtrace,
57                )
58            }
59            None => {
60                format!(
61                    "thread '{}' panicked at '{}'\n{}",
62                    thread,
63                    msg,
64                    backtrace.clone()
65                )
66            }
67        };
68
69        msg
70    }
71
72    fn format_backtrace_with_symbol(backtrace: &Backtrace) -> String {
73        format!("{:?}", backtrace)
74    }
75
76    fn format_backtrace(backtrace: &Backtrace) -> String {
77        let frames: Vec<BacktraceFrame> = backtrace.clone().into();
78        let mut values = Vec::new();
79        for (i, frame) in frames.into_iter().enumerate() {
80            if let Some(mod_addr) = frame.module_base_address() {
81                let offset = frame.symbol_address() as isize - mod_addr as isize;
82                values.push(format!("{}: {:#018x} {:#018p}", i, offset, mod_addr));
83            } else {
84                values.push(format!("{}: {:#018p}", i, frame.symbol_address()));
85            }
86        }
87
88        values.join("\n")
89    }
90
91    fn calc_hash(backtrace: &Backtrace) -> String {
92        let mut sha256 = sha2::Sha256::new();
93
94        let frames: Vec<BacktraceFrame> = backtrace.clone().into();
95        let mut values = Vec::new();
96        for (i, frame) in frames.into_iter().enumerate() {
97            if let Some(mod_addr) = frame.module_base_address() {
98                let offset = frame.symbol_address() as isize - mod_addr as isize;
99                values.push(format!("{}:{}", i, offset));
100            } else {
101                values.push(format!("{}:{:p}", i, frame.symbol_address()));
102            }
103        }
104
105        let all = values.join("\n");
106
107        sha256.input(all);
108        let ret = sha256.result();
109        let hash = hex::encode(ret);
110
111        // 只截取前32个字节
112        let hash = hash[..32].to_owned();
113
114        info!("stack_hash=\n{}", hash);
115
116        hash
117    }
118}