1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16//! panic handler for Rust. 17#![feature(rustc_private)] 18extern crate hisysevent; 19extern crate libc; 20extern crate stacktrace_rust; 21use std::ffi::CString; 22use std::fs; 23use std::os::raw::{c_char}; 24use std::panic; 25use std::panic::PanicInfo; 26use std::process; 27use std::time::{UNIX_EPOCH, SystemTime}; 28use hilog_rust::{error, hilog, HiLogLabel, LogType}; 29use hisysevent::{EventType}; 30 31const LOG_LABEL: HiLogLabel = HiLogLabel { 32 log_type: LogType::LogCore, 33 domain: 0xD002D11, 34 tag: "DfxFaultLogger" 35}; 36 37/// panic handler 38fn panic_handler() { 39 panic::set_hook(Box::new(move |info| { 40 report_info_handler(info) 41 })); 42} 43 44fn read_process_name(pid: u32) -> String { 45 let path = format!("/proc/{}/cmdline", pid); 46 let binding = fs::read_to_string(path).unwrap(); 47 let mut process_name = binding.as_str(); 48 if process_name.find('\0').is_some() { 49 (process_name, _) = process_name.split_at(process_name.find('\0').unwrap()); 50 } 51 if process_name.rfind('/').is_some() { 52 (_, process_name) = process_name.split_at(process_name.rfind('/').unwrap() + 1); 53 } 54 process_name.to_string() 55} 56 57fn read_thread_name(pid: u32) -> String { 58 let path = format!("/proc/{}/comm", pid); 59 fs::read_to_string(path).unwrap() 60} 61 62#[allow(unused_variables)] 63fn report_info_handler(info: &PanicInfo) { 64 let (file, line) = info.location().map(|loc| (loc.file(), loc.line())).unwrap_or(("<unknown>", 0)); 65 let errmsg = match info.payload().downcast_ref::<&'static str>() { 66 Some(s) => *s, 67 None => match info.payload().downcast_ref::<String>() { 68 Some(s) => &**s, 69 None => "Box<Any>", 70 }, 71 }; 72 73 let pid = process::id(); 74 let process_name = read_process_name(pid); 75 let thread_name = read_thread_name(pid); 76 let panic_reason = format!("file:{} line:{} message:{}", file, line, errmsg); 77 let thread_label = format!("Thread name:{}{}", thread_name, stacktrace_rust::get_trace(true).as_str()); 78 let happen_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis(); 79 let ret = hisysevent::write( 80 "RELIABILITY", 81 "RUST_PANIC", 82 EventType::Fault, 83 &[hisysevent::build_str_param!("MODULE", process_name.as_str()), 84 hisysevent::build_str_param!("REASON", panic_reason.as_str()), 85 hisysevent::build_number_param!("PID", pid), 86 hisysevent::build_number_param!("TID", unsafe { libc::gettid() }), 87 hisysevent::build_number_param!("UID", unsafe { libc::getuid() }), 88 hisysevent::build_str_param!("SUMMARY", thread_label.as_str()), 89 hisysevent::build_number_param!("HAPPEN_TIME", happen_time) 90 ] 91 ); 92 if ret != 0 { 93 error!(LOG_LABEL, "RUST_PANIC hisysevent write failed"); 94 } 95} 96 97/// Initializes the panic hook 98pub fn init() { 99 panic_handler(); 100}