llvm_plugin_inkwell/support/
error_handling.rs

1//! This module contains some supplemental functions for dealing with errors.
2
3use libc::c_void;
4use llvm_sys::core::{LLVMGetDiagInfoDescription, LLVMGetDiagInfoSeverity};
5use llvm_sys::error_handling::{LLVMInstallFatalErrorHandler, LLVMResetFatalErrorHandler};
6use llvm_sys::prelude::LLVMDiagnosticInfoRef;
7use llvm_sys::LLVMDiagnosticSeverity;
8
9// REVIEW: Maybe it's possible to have a safe wrapper? If we can
10// wrap the provided function input ptr into a &CStr somehow
11// TODOC: Can be used like this:
12// extern "C" fn print_before_exit(msg: *const i8) {
13//    let c_str = unsafe { ::std::ffi::CStr::from_ptr(msg) };
14//
15//    eprintln!("LLVM fatally errored: {:?}", c_str);
16// }
17// unsafe {
18//     install_fatal_error_handler(print_before_exit);
19// }
20// and will be called before LLVM calls C exit()
21/// Installs an error handler to be called before LLVM exits.
22pub unsafe fn install_fatal_error_handler(handler: extern "C" fn(*const ::libc::c_char)) {
23    LLVMInstallFatalErrorHandler(Some(handler))
24}
25
26/// Resets LLVM's fatal error handler back to the default
27pub fn reset_fatal_error_handler() {
28    unsafe { LLVMResetFatalErrorHandler() }
29}
30
31pub(crate) struct DiagnosticInfo {
32    diagnostic_info: LLVMDiagnosticInfoRef,
33}
34
35impl DiagnosticInfo {
36    pub unsafe fn new(diagnostic_info: LLVMDiagnosticInfoRef) -> Self {
37        DiagnosticInfo { diagnostic_info }
38    }
39
40    pub(crate) fn get_description(&self) -> *mut ::libc::c_char {
41        unsafe { LLVMGetDiagInfoDescription(self.diagnostic_info) }
42    }
43
44    pub(crate) fn severity_is_error(&self) -> bool {
45        unsafe {
46            match LLVMGetDiagInfoSeverity(self.diagnostic_info) {
47                LLVMDiagnosticSeverity::LLVMDSError => true,
48                _ => false,
49            }
50        }
51    }
52}
53
54// Assmuptions this handler makes:
55// * A valid *mut *mut i8 is provided as the void_ptr (via context.set_diagnostic_handler)
56//
57// https://github.com/llvm-mirror/llvm/blob/master/tools/llvm-c-test/diagnostic.c was super useful
58// for figuring out how to get this to work
59pub(crate) extern "C" fn get_error_str_diagnostic_handler(
60    diagnostic_info: LLVMDiagnosticInfoRef,
61    void_ptr: *mut c_void,
62) {
63    let diagnostic_info = unsafe { DiagnosticInfo::new(diagnostic_info) };
64
65    if diagnostic_info.severity_is_error() {
66        let c_ptr_ptr = void_ptr as *mut *mut c_void as *mut *mut ::libc::c_char;
67
68        unsafe {
69            *c_ptr_ptr = diagnostic_info.get_description();
70        }
71    }
72}