Skip to content

Commit ac7833c

Browse files
author
Ariel Ben-Yehuda
committed
add a native C demangler
1 parent f053741 commit ac7833c

File tree

9 files changed

+2319
-0
lines changed

9 files changed

+2319
-0
lines changed

crates/native-c/Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "rustc-demangle-native-c"
3+
version = "0.1.0"
4+
authors = ["automatically generated"]
5+
description = """
6+
Native C version of the rustc_demangle crate
7+
"""
8+
license = "MIT/Apache-2.0"
9+
repository = "https://github.com/rust-lang/rustc-demangle"
10+
11+
[lib]
12+
name = "rustc_demangle_native_c"
13+
14+
[build-dependencies]
15+
cc = "1"

crates/native-c/README

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
A portable native C demangler, which should mostly have byte-for-byte identical outputs to the Rust one.
2+
3+
The only difference is that since it's hard to include up-to-date unicode tables in portable C code, strings in constants (do you know that feature exists?) have all non-ASCII characters escaped (as `\u{ABCD}`) rather than having only non-printable characters escaped. Unicode in identifiers is still translated as-is, allowing non-printable characters just like rustc. If you care, the code intentionally includes `unicode_isprint` and `unicode_isgraphemextend` that can be replaced with actual Unicode tables.
4+
5+
This has a Cargo.toml to make it easy to test, but people whose build systems can use Rust are expected to use the `capi` directory instead. Since the crate is intended only for users with weird build systems, there is no build system provided.

crates/native-c/build.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
cc::Build::new()
3+
.file("src/demangle.c")
4+
.include("include")
5+
.compile("demangle_native_c");
6+
println!("cargo::rerun-if-changed=src/demangle.c");
7+
println!("cargo::rerun-if-changed=include/demangle.h");
8+
}

crates/native-c/include/demangle.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#ifndef _H_DEMANGLE_V0_H
2+
#define _H_DEMANGLE_V0_H
3+
4+
#include <stddef.h>
5+
6+
#if defined(__GNUC__) || defined(__clang__)
7+
#define DEMANGLE_NODISCARD __attribute__((warn_unused_result))
8+
#else
9+
#define DEMANGLE_NODISCARD
10+
#endif
11+
12+
typedef enum {
13+
OverflowOk,
14+
OverflowOverflow
15+
} overflow_status;
16+
17+
enum demangle_style {
18+
DemangleStyleUnknown = 0,
19+
DemangleStyleLegacy,
20+
DemangleStyleV0,
21+
};
22+
23+
// Not using a union here to make the struct easier to copy-paste if needed.
24+
struct demangle {
25+
enum demangle_style style;
26+
// points to the "mangled" part of the name,
27+
// not including `ZN` or `R` prefixes.
28+
const char *mangled;
29+
size_t mangled_len;
30+
// In DemangleStyleLegacy, is the number of path elements
31+
size_t elements;
32+
// while it's called "original", it will not contain `.llvm.9D1C9369@@16` suffixes
33+
// that are to be ignored.
34+
const char *original;
35+
size_t original_len;
36+
// Contains the part after the mangled name that is to be outputted,
37+
// which can be `.exit.i.i` suffixes LLVM sometimes adds.
38+
const char *suffix;
39+
size_t suffix_len;
40+
};
41+
42+
// if the length of the output buffer is less than `output_len-OVERFLOW_MARGIN`,
43+
// the demangler will return `OverflowOverflow` even if there is no overflow.
44+
#define OVERFLOW_MARGIN 4
45+
46+
/// Demangle a C string that refers to a Rust symbol and put the demangle intermediate result in `res`.
47+
/// Beware that `res` contains references into `s`. If `s` is modified (or free'd) before calling
48+
/// `rust_demangle_display_demangle` behavior is undefined.
49+
///
50+
/// Use `rust_demangle_display_demangle` to convert it to an actual string.
51+
void rust_demangle_demangle(const char *s, struct demangle *res);
52+
53+
/// Write the string in a `struct demangle` into a buffer.
54+
///
55+
/// Return `OverflowOk` if the output buffer was sufficiently big, `OverflowOverflow` if it wasn't.
56+
/// This function is `O(n)` in the length of the input + *output* [$], but the demangled output of demangling a symbol can
57+
/// be exponentially[$$] large, therefore it is recommended to have a sane bound (`rust-demangle`
58+
/// uses 1,000,000 bytes) on `len`.
59+
///
60+
/// `alternate`, if true, uses the less verbose alternate formatting (Rust `{:#}`) is used, which does not show
61+
/// symbol hashes and types of constant ints.
62+
///
63+
/// [$] It's `O(n * MAX_DEPTH)`, but `MAX_DEPTH` is a constant 300 and therefore it's `O(n)`
64+
/// [$$] Technically, bounded by `O(n^MAX_DEPTH)`, but this is practically exponential.
65+
DEMANGLE_NODISCARD overflow_status rust_demangle_display_demangle(struct demangle const *res, char *out, size_t len, bool alternate);
66+
67+
/// Returns true if `res` refers to a known valid Rust demangling style, false if it's an unknown style.
68+
bool rust_demangle_is_known(struct demangle *res);
69+
70+
#undef DEMANGLE_NODISCARD
71+
72+
#endif

crates/native-c/src/build.rs

Whitespace-only changes.

0 commit comments

Comments
 (0)