]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-demangler/src/main.rs
Rollup merge of #102445 - jmillikin:cstr-is-empty, r=Mark-Simulacrum
[rust.git] / src / tools / rust-demangler / src / main.rs
1 //! Demangles rustc mangled names.
2 //!
3 //! Note regarding crate disambiguators:
4 //!
5 //! Some demangled symbol paths can include "crate disambiguator" suffixes, represented as a large
6 //! hexadecimal value enclosed in square braces, and appended to the name of the crate. a suffix to the
7 //! original crate name. For example, the `core` crate, here, includes a disambiguator:
8 //!
9 //! ```rust
10 //!     <generics::Firework<f64> as core[a7a74cee373f048]::ops::drop::Drop>::drop
11 //! ```
12 //!
13 //! These disambiguators are known to vary depending on environmental circumstances. As a result,
14 //! tests that compare results including demangled names can fail across development environments,
15 //! particularly with cross-platform testing. Also, the resulting crate paths are not syntactically
16 //! valid, and don't match the original source symbol paths, which can impact development tools.
17 //!
18 //! For these reasons, by default, `rust-demangler` uses a heuristic to remove crate disambiguators
19 //! from their original demangled representation before printing them to standard output. If crate
20 //! disambiguators are required, add the `-d` (or `--disambiguators`) flag, and the disambiguators
21 //! will not be removed.
22 //!
23 //! Also note that the disambiguators are stripped by a Regex pattern that is tolerant to some
24 //! variation in the number of hexadecimal digits. The disambiguators come from a hash value, which
25 //! typically generates a 16-digit hex representation on a 64-bit architecture; however, leading
26 //! zeros are not included, which can shorten the hex digit length, and a different hash algorithm
27 //! that might also be dependent on the architecture, might shorten the length even further. A
28 //! minimum length of 5 digits is assumed, which should be more than sufficient to support hex
29 //! representations that generate only 8-digits of precision with an extremely rare (but not
30 //! impossible) result with up to 3 leading zeros.
31 //!
32 //! Using a minimum number of digits less than 5 risks the possibility of stripping demangled name
33 //! components with a similar pattern. For example, some closures instantiated multiple times
34 //! include their own disambiguators, demangled as non-hashed zero-based indexes in square brackets.
35 //! These disambiguators seem to have more analytical value (for instance, in coverage analysis), so
36 //! they are not removed.
37
38 use rust_demangler::*;
39 use std::io::{self, Read, Write};
40
41 fn main() -> io::Result<()> {
42     // FIXME(richkadel): In Issue #77615 discussed updating the `rustc-demangle` library, to provide
43     // an option to generate demangled names without including crate disambiguators. If that
44     // happens, update this tool to use that option (if the `-d` flag is not set) instead stripping
45     // them via the Regex heuristic. The update the doc comments and help.
46
47     // Strip hashed hexadecimal crate disambiguators. Leading zeros are not enforced, and can be
48     // different across different platform/architecture types, so while 16 hex digits are common,
49     // they can also be shorter.
50     //
51     // Also note that a demangled symbol path may include the `[<digits>]` pattern, with zero-based
52     // indexes (such as for closures, and possibly for types defined in anonymous scopes). Preferably
53     // these should not be stripped.
54     //
55     // The minimum length of 5 digits supports the possibility that some target architecture (maybe
56     // a 32-bit or smaller architecture) could generate a hash value with a maximum of 8 digits,
57     // and more than three leading zeros should be extremely unlikely. Conversely, it should be
58     // sufficient to assume the zero-based indexes for closures and anonymous scopes will never
59     // exceed the value 9999.
60     let mut strip_crate_disambiguators = Some(create_disambiguator_re());
61
62     let mut args = std::env::args();
63     let progname = args.next().unwrap();
64     for arg in args {
65         if arg == "--disambiguators" || arg == "-d" {
66             strip_crate_disambiguators = None;
67         } else {
68             eprintln!();
69             eprintln!("Usage: {} [-d|--disambiguators]", progname);
70             eprintln!();
71             eprintln!(
72                 "This tool converts a list of Rust mangled symbols (one per line) into a\n\
73                 corresponding list of demangled symbols."
74             );
75             eprintln!();
76             eprintln!(
77                 "With -d (--disambiguators), Rust symbols mangled with the v0 symbol mangler may\n\
78                 include crate disambiguators (a hexadecimal hash value, typically up to 16 digits\n\
79                 long, enclosed in square brackets)."
80             );
81             eprintln!();
82             eprintln!(
83                 "By default, crate disambiguators are removed, using a heuristics-based regular\n\
84                 expression. (See the `rust-demangler` doc comments for more information.)"
85             );
86             eprintln!();
87             std::process::exit(1)
88         }
89     }
90
91     let mut buffer = String::new();
92     io::stdin().read_to_string(&mut buffer)?;
93     let mut demangled_lines = demangle_lines(buffer.lines(), strip_crate_disambiguators);
94     demangled_lines.push("".to_string()); // ensure a trailing newline
95     io::stdout().write_all(demangled_lines.join("\n").as_bytes())?;
96     Ok(())
97 }