cplus_demangle/lib.rs
1//! # cplus_demangle
2//! [](https://crates.io/crates/cplus_demangle) [](https://docs.rs/cplus_demangle/latest/cplus_demangle/)
3//!
4//! This library converts C++ mangled symbol names to human-readable strings. It is a safe Rust wrapper to GNU libiberty's C function `cplus_demangle`.
5//!
6//! ## Example
7//! Suppose you compile the following C++ program:
8//! ```cpp
9//! namespace test {
10//! void myfn(int x) { }
11//! }
12//! ```
13//!
14//! In the resulting binary, the symbol that gets generated for `myfn` is `_ZN4test4myfnEi`. We can convert it back with this Rust code:
15//! ```rust
16//! assert_eq!(cplus_demangle::demangle("_ZN4test4myfnEi").unwrap(), "test::myfn(int)");
17//! ```
18
19use libc::{c_char, c_int};
20use std::ffi::{CStr, CString};
21
22extern "C" {
23 fn cplus_demangle_wrapper(
24 mangled_name: *const c_char,
25 show_params: c_int,
26 show_ansi: c_int,
27 ) -> *mut c_char;
28}
29
30#[derive(Debug)]
31pub struct Error(&'static str);
32
33/// Description of options from demangle.h:
34/// ```
35/// #define DMGL_PARAMS (1 << 0) /* Include function args */
36/// #define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
37/// ```
38pub struct Options {
39 pub show_params: bool,
40 pub show_ansi: bool,
41}
42
43impl Options {
44 pub fn default() -> Options {
45 Options {
46 show_params: true,
47 show_ansi: true,
48 }
49 }
50}
51
52/// Demangle the given name, with default options.
53pub fn demangle(mangled_name: &str) -> Result<String, Error> {
54 demangle_with_options(mangled_name, Options::default())
55}
56
57/// Demangle the given name with the specified options.
58///
59/// Fails if: the name contains a null character, or demangling fails.
60pub fn demangle_with_options(mangled_name: &str, options: Options) -> Result<String, Error> {
61 let mangled_name = match CString::new(mangled_name) {
62 Ok(mangled_name) => mangled_name,
63 Err(std::ffi::NulError { .. }) => return Err(Error("mangled_name contains null")),
64 };
65 let result: *mut c_char = unsafe {
66 cplus_demangle_wrapper(
67 mangled_name.as_ptr(),
68 options.show_params as i32,
69 options.show_ansi as i32,
70 )
71 };
72 if result.is_null() {
73 // Unfortunately cplus_demangle appears to give us precisely 0 helpful
74 // error info, we have to go with a generic message.
75 return Err(Error("Failed to demangle"));
76 }
77 let demangled = unsafe { CStr::from_ptr(result) };
78 Ok(demangled.to_str().unwrap().to_owned())
79}
80
81#[cfg(test)]
82mod tests {
83 #[test]
84 fn it_works() {
85 assert_eq!(
86 crate::demangle("_ZNK5boost16cpp_regex_traitsIcE7isctypeEcj").unwrap(),
87 "boost::cpp_regex_traits<char>::isctype(char, unsigned int) const"
88 );
89 assert_eq!(
90 crate::demangle_with_options(
91 "_ZNK5boost16cpp_regex_traitsIcE7isctypeEcj",
92 crate::Options {
93 show_params: false,
94 show_ansi: true,
95 }
96 )
97 .unwrap(),
98 "boost::cpp_regex_traits<char>::isctype"
99 );
100 }
101}