blob: 0c7d69b4ef71db25d0813777c486a31b1b3ae681 [file] [log] [blame]
use std::ffi::{c_char, c_int};
/// struct demangle
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CDemangle {
style: c_int,
mangled: *const c_char,
mangled_len: usize,
elements: usize,
// 32
original: *const c_char,
original_len: usize,
suffix: *const c_char,
suffix_len: usize,
}
impl CDemangle {
/// Create an empty `struct demangle`
pub fn zero() -> Self {
Self {
style: 0,
mangled: core::ptr::null(),
mangled_len: 0,
elements: 0,
original: core::ptr::null(),
original_len: 0,
suffix: core::ptr::null(),
suffix_len: 0,
}
}
}
extern "C" {
/// call rust_demangle_demangle
pub fn rust_demangle_demangle(s: *const c_char, res: *mut CDemangle);
/// call rust_demangle_display_demangle
pub fn rust_demangle_display_demangle(
res: *const CDemangle,
out: *mut c_char,
len: usize,
alternate: bool,
) -> c_int;
}
#[test]
fn smoke_test() {
fn test_single(input: &str, expected: &str, alternate: bool) {
use std::ffi::{CStr, CString};
let mut buf = [0u8; 4096];
unsafe {
let mut demangle = CDemangle::zero();
let cs = CString::new(input).unwrap();
for output_len in 0..4096 {
rust_demangle_demangle(cs.as_ptr(), &mut demangle);
if rust_demangle_display_demangle(
&demangle,
buf.as_mut_ptr().cast(),
output_len,
alternate,
) != 0
{
continue; // buffer is not big enough
}
let output = CStr::from_bytes_until_nul(&buf[..])
.expect("nul")
.to_str()
.expect("utf-8");
assert_eq!(output, expected);
// test overflow margin
assert_eq!(output_len, output.len() + 4);
return;
}
panic!("overflow");
}
}
for (input, normal, alternate) in [
// test empty string
("", "", ""),
// just a path
("_RNvC6_123foo3bar", "123foo::bar", "123foo::bar"),
// more complex paths
("_RNCNCNgCs6DXkGYLi8lr_2cc5spawn00B5_", "cc[4d6468d6c9fd4bb3]::spawn::{closure#0}::{closure#0}", "cc::spawn::{closure#0}::{closure#0}"),
("_RINbNbCskIICzLVDPPb_5alloc5alloc8box_freeDINbNiB4_5boxed5FnBoxuEp6OutputuEL_ECs1iopQbuBiw2_3std", "alloc[f15a878b47eb696b]::alloc::box_free::<dyn alloc[f15a878b47eb696b]::boxed::FnBox<(), Output = ()>>", "alloc::alloc::box_free::<dyn alloc::boxed::FnBox<(), Output = ()>>"),
("_RMC0INtC8arrayvec8ArrayVechKj7b_E", "<arrayvec::ArrayVec<u8, 123usize>>", "<arrayvec::ArrayVec<u8, 123>>"),
// punycode
("_RNqCs4fqI2P2rA04_11utf8_identsu30____7hkackfecea1cbdathfdh9hlq6y", "utf8_idents[317d481089b8c8fe]::საჭმელად_გემრიელი_სადილი", "utf8_idents::საჭმელად_გემრიელი_სადილი"),
// string with non-utf8 characters
("_RIC0Kef09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e29895f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_E",
"::<{*\"\\u{1f40a}\\u{1f988}\\u{1f986}\\u{1f42e} \\u{a7} \\u{1f436}\\u{1f452}\\u{2615}\\u{1f525} \\u{a7} \\u{1f9e1}\\u{1f49b}\\u{1f49a}\\u{1f499}\\u{1f49c}\"}>",
"::<{*\"\\u{1f40a}\\u{1f988}\\u{1f986}\\u{1f42e} \\u{a7} \\u{1f436}\\u{1f452}\\u{2615}\\u{1f525} \\u{a7} \\u{1f9e1}\\u{1f49b}\\u{1f49a}\\u{1f499}\\u{1f49c}\"}>"
),
// invalid syntax via backref
("_RNvNvB0_1x1y", "{invalid syntax}::x::y", "{invalid syntax}::x::y"),
// overflow via backref
("_RNvNvB1_1x1y",
"{recursion limit reached}::?::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::y",
"{recursion limit reached}::?::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::x::y",
),
// native
("_ZN9backtrace3foo17hbb467fcdaea5d79bE.llvm.A5310EB9", "backtrace::foo::hbb467fcdaea5d79b", "backtrace::foo"),
// LLVM suffix
("_RNvC6_123foo3bar.llvm.A5310EB9", "123foo::bar", "123foo::bar"),
("_ZN9backtrace3foo17hbb467fcdaea5d79bE.llvm.A5310EB9", "backtrace::foo::hbb467fcdaea5d79b", "backtrace::foo"),
// other suffix
("_RNvC6_123foo3bar.i", "123foo::bar.i", "123foo::bar.i"),
("_ZN9backtrace3foo17hbb467fcdaea5d79bE.i", "backtrace::foo::hbb467fcdaea5d79b.i", "backtrace::foo.i"),
] {
test_single(input, normal, false);
test_single(input, alternate, true);
}
}