Rust栈回溯与异常处理库unwind-sys的使用,unwind-sys提供底层堆栈展开和异常处理功能

Rust栈回溯与异常处理库unwind-sys的使用

unwind-sys是一个提供底层堆栈展开和异常处理功能的Rust库。它是rstack项目的一部分,主要用作其他更高级别库的基础设施。

安装

在项目目录中运行以下Cargo命令:

cargo add unwind-sys

或在Cargo.toml中添加:

unwind-sys = "0.1.4"

基本使用示例

以下是一个使用unwind-sys进行栈回溯的简单示例:

extern crate unwind_sys;

use unwind_sys::{
    _Unwind_Backtrace, _Unwind_Context, _Unwind_GetIP, _Unwind_Reason_Code,
    _URC_NO_REASON, _URC_END_OF_STACK
};

// 回调函数类型
type Callback = extern "C" fn(context: *mut _Unwind_Context, arg: *mut libc::c_void) -> _Unwind_Reason_Code;

// 栈回溯回调函数
extern "C" fn backtrace_callback(context: *mut _Unwind_Context, arg: *mut libc::c_void) -> _Unwind_Reason_Code {
    unsafe {
        let ip = _Unwind_GetIP(context);
        if ip != 0 {
            println!("Frame at {:p}", ip as *const libc::c_void);
        }
        _URC_NO_REASON
    }
}

fn main() {
    println!("Starting stack trace...");
    
    unsafe {
        _Unwind_Backtrace(backtrace_callback, std::ptr::null_mut());
    }
    
    println!("Stack trace completed.");
}

完整示例

下面是一个更完整的示例,展示了如何使用unwind-sys进行异常处理和栈回溯:

extern crate unwind_sys;
extern crate libc;

use unwind_sys::{
    _Unwind_Backtrace, _Unwind_Context, _Unwind_GetIP, _Unwind_Reason_Code,
    _URC_NO_REASON, _URC_END_OF_STACK,
    _Unwind_GetLanguageSpecificData, _Unwind_GetRegionStart,
    _Unwind_SetGR, _Unwind_SetIP
};

// 自定义异常结构
#[repr(C)]
struct Exception {
    exception_class: u64,
    exception_cleanup: extern "C" fn(unwind_code: u64, exception: *mut Exception),
    private_1: u64,
    private_2: u64,
}

// 异常处理回调函数
extern "C" fn personality(
    version: i32,
    actions: unwind_sys::_Unwind_Action,
    exception_class: u64,
    exception: *mut unwind_sys::_Unwind_Exception,
    context: *mut unwind_sys::_Unwind_Context,
) -> unwind_sys::_Unwind_Reason_Code {
    unsafe {
        println!("Personality function called");
        _URC_NO_REASON
    }
}

// 栈回溯回调函数
extern "C" fn backtrace_callback(context: *mut _Unwind_Context, arg: *mut libc::c_void) -> _Unwind_Reason_Code {
    unsafe {
        let ip = _Unwind_GetIP(context);
        if ip != 0 {
            println!("Frame at {:p}", ip as *const libc::c_void);
            
            // 获取语言特定数据
            let lsd = _Unwind_GetLanguageSpecificData(context);
            if !lsd.is_null() {
                println!("  Language specific data available");
            }
            
            // 获取区域起始地址
            let region_start = _Unwind_GetRegionStart(context);
            println!("  Region starts at {:p}", region_start as *const libc::c_void);
        }
        _URC_NO_REASON
    }
}

fn throw_exception() {
    println!("Preparing to throw exception");
    
    let mut exception = Exception {
    exception_class: 0x12345678,
    exception_cleanup: cleanup_handler,
    private_1: 0,
    private_2: 0,
    };
    
    unsafe {
        // 模拟异常抛出
        unwind_sys::_Unwind_RaiseException(&mut exception as *mut _ as *mut _);
    }
    
    println!("This line should not be reached");
}

// 异常清理处理函数
extern "C" fn cleanup_handler(unwind_code: u64, exception: *mut Exception) {
    println!("Cleanup handler called with code: {}", unwind_code);
}

fn main() {
    println!("Starting stack trace...");
    
    unsafe {
        _Unwind_Backtrace(backtrace_callback, std::ptr::null_mut());
    }
    
    println!("Attempting to throw and catch exception...");
    throw_exception();
    
    println!("Program completed successfully");
}

注意事项

  1. unwind-sys是一个低级库,通常不直接使用,而是作为更高级别栈回溯或异常处理库的基础
  2. 使用时需要特别注意内存安全和未定义行为
  3. 跨平台兼容性可能存在问题,不同平台的实现可能有差异

文档

更详细的文档可以在相关文档站点找到。

源码

项目源码位于相关代码托管平台。


1 回复

Rust栈回溯与异常处理库unwind-sys的使用指南

简介

unwind-sys是Rust中一个提供底层堆栈展开(backtrace)和异常处理功能的库。它是libunwind的Rust绑定,主要用于需要处理异常或获取调用堆栈信息的场景。

主要功能

  1. 提供堆栈展开(backtrace)功能
  2. 实现异常处理机制
  3. 支持跨平台的底层栈操作

使用方法

添加依赖

首先在Cargo.toml中添加依赖:

[dependencies]
unwind-sys = "0.1"

基本示例:获取堆栈回溯

use unwind_sys::{unw_getcontext, unw_init_local, unw_step};

fn print_backtrace() {
    let mut context = std::mem::MaybeUninit::uninit();
    let mut cursor = std::mem::MaybeUninit::uninit();
    
    unsafe {
        // 获取当前上下文
        unw_getcontext(context.as_mut_ptr());
        
        // 初始化本地游标
        unw_init_local(cursor.as_mut_ptr(), context.as_mut_ptr());
        
        let mut cursor = cursor.assume_init();
        
        // 遍历调用栈
        while unw_step(&mut cursor) > 0 {
            let mut offset = 0;
            let mut name = [0u8; 1024];
            
            // 获取函数名
            unw_get_proc_name(&mut cursor, name.as_mut_ptr(), name.len(), &mut offset);
            
            if let Ok(name_str) = std::ffi::CStr::from_ptr(name.as_ptr()).to_str() {
                println!("{}", name_str);
            }
        }
    }
}

异常处理示例

use unwind_sys::{_Unwind_Reason_Code, _Unwind_Action, _Unwind_Exception};

extern "C" fn personality_handler(
    version: i32,
    actions: _Unwind_Action,
    exception_class: u64,
    exception: *mut _Unwind_Exception,
    context: *mut unwind_sys::_Unwind_Context,
) -> _Unwind_Reason_Code {
    // 处理异常逻辑
    println!("Exception occurred!");
    
    // 继续传播异常
    _Unwind_Reason_Code::_URC_CONTINUE_UNWIND
}

fn setup_exception_handler() {
    unsafe {
        unwind_sys::_Unwind_SetPersonalityFn(Some(personality_handler));
    }
}

高级用法

自定义异常类型

use unwind_sys::{_Unwind_Exception, _Unwind_Exception_Class};

struct MyException {
    exception: _Unwind_Exception,
    data: String,
}

impl MyException {
    fn new(message: String) -> Self {
        MyException {
            exception: _Unwind_Exception {
                exception_class: MyException::exception_class(),
                exception_cleanup: Some(MyException::cleanup),
                private: [0; unwind_sys::unwinder_private_data_size],
            },
            data: message,
        }
    }
    
    fn exception_class() -> _Unwind_Exception_Class {
        // 生成唯一的异常类标识符
        let mut class = [0u8; 8];
        class.copy_from_slice(b"MYEXCEPT");
        u64::from_ne_bytes(class)
    }
    
    extern "C" fn cleanup(_unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception) {
        unsafe {
            // 将指针转换回MyException并释放内存
            let ex = Box::from_raw(exception as *mut MyException);
            println!("Cleaning up exception: {}", ex.data);
        }
    }
}

完整示例demo

以下是一个结合了堆栈回溯和异常处理的完整示例:

use unwind_sys::{
    unw_getcontext, unw_init_local, unw_step, unw_get_proc_name,
    _Unwind_Reason_Code, _Unwind_Action, _Unwind_Exception, _Unwind_Exception_Class,
    _Unwind_SetPersonalityFn, _Unwind_Context
};
use std::ffi::CStr;
use std::mem::MaybeUninit;

// 自定义异常类型
struct CustomException {
    exception: _Unwind_Exception,
    message: String,
}

impl CustomException {
    fn new(msg: String) -> Self {
        CustomException {
            exception: _Unwind_Exception {
                exception_class: Self::exception_class(),
                exception_cleanup: Some(Self::cleanup),
                private: [0; unwind_sys::unwinder_private_data_size],
            },
            message: msg,
        }
    }

    fn exception_class() -> _Unwind_Exception_Class {
        let mut class = [0u8; 8];
        class.copy_from_slice(b"CUSTOMEX");
        u64::from_ne_bytes(class)
    }

    extern "C" fn cleanup(_code: _Unwind_Reason_Code, ex: *mut _Unwind_Exception) {
        unsafe {
            let this = Box::from_raw(ex as *mut CustomException);
            println!("Cleanup: {}", this.message);
        }
    }
}

// 异常处理回调
extern "C" fn personality_handler(
    _version: i32,
    _actions: _Unwind_Action,
    _exception_class: u64,
    _exception: *mut _Unwind_Exception,
    _context: *mut _Unwind_Context,
) -> _Unwind_Reason_Code {
    println!("Personality handler called");
    _Unwind_Reason_Code::_URC_CONTINUE_UNWIND
}

// 打印调用栈
fn print_stack_trace() {
    unsafe {
        let mut context = MaybeUninit::uninit();
        let mut cursor = MaybeUninit::uninit();
        
        unw_getcontext(context.as_mut_ptr());
        unw_init_local(cursor.as_mut_ptr(), context.as_mut_ptr());
        
        let mut cursor = cursor.assume_init();
        println!("Stack trace:");
        
        while unw_step(&mut cursor) > 0 {
            let mut offset = 0;
            let mut name = [0u8; 1024];
            
            unw_get_proc_name(&mut cursor, name.as_mut_ptr(), name.len(), &mut offset);
            
            if let Ok(name_str) = CStr::from_ptr(name.as_ptr()).to_str() {
                println!("  {}", name_str);
            }
        }
    }
}

fn main() {
    // 设置异常处理
    unsafe {
        _Unwind_SetPersonalityFn(Some(personality_handler));
    }
    
    // 打印当前调用栈
    print_stack_trace();
    
    // 创建并抛出自定义异常
    let ex = Box::new(CustomException::new("Test exception".to_string()));
    let ex_ptr = Box::into_raw(ex) as *mut _Unwind_Exception;
    
    unsafe {
        // 模拟抛出异常
        println!("Throwing exception...");
        unwind_sys::_Unwind_RaiseException(ex_ptr);
    }
    
    println!("This line will not be reached");
}

注意事项

  1. unwind-sys是底层库,使用时需要特别注意内存安全
  2. 跨平台行为可能不一致,需要测试目标平台
  3. 异常处理机制与Rust的panic系统不同,不能直接替代
  4. 性能敏感场景需要评估使用成本

总结

unwind-sys为Rust提供了强大的底层堆栈操作和异常处理能力,适合需要深度控制执行流程或实现自定义错误处理机制的场景。使用时应当充分理解其底层原理并做好安全防护。

回到顶部