1 // For clippy.
2 #![allow(unknown_lints)]
3
4 extern crate cpp_demangle;
5
6 // For command line integration
7 #[macro_use]
8 extern crate clap;
9
10 use clap::{App, Arg};
11 use cpp_demangle::{BorrowedSymbol, DemangleOptions};
12 use std::io::{self, BufRead, Cursor, Write};
13 use std::process;
14
15 /// Find the index of the first (potential) occurrence of a mangled C++ symbol
16 /// in the given `haystack`.
find_mangled(haystack: &[u8]) -> Option<usize>17 fn find_mangled(haystack: &[u8]) -> Option<usize> {
18 if haystack.is_empty() {
19 return None;
20 }
21
22 for i in 0..haystack.len() - 1 {
23 if haystack[i] == b'_' {
24 match (
25 haystack[i + 1],
26 haystack.get(i + 2),
27 haystack.get(i + 3),
28 haystack.get(i + 4),
29 ) {
30 (b'Z', _, _, _) | (b'_', Some(b'Z'), _, _) | (b'_', Some(b'_'), Some(b'Z'), _) => {
31 return Some(i)
32 }
33 (b'_', Some(b'_'), Some(b'_'), Some(b'Z')) => return Some(i),
34 _ => (),
35 }
36 }
37 }
38
39 None
40 }
41
42 /// Print the given `line` to `out`, with all mangled C++ symbols replaced with
43 /// their demangled form.
demangle_line<W>(out: &mut W, line: &[u8], options: DemangleOptions) -> io::Result<()> where W: Write,44 fn demangle_line<W>(out: &mut W, line: &[u8], options: DemangleOptions) -> io::Result<()>
45 where
46 W: Write,
47 {
48 let mut line = line;
49
50 while let Some(idx) = find_mangled(line) {
51 write!(out, "{}", String::from_utf8_lossy(&line[..idx]))?;
52
53 if let Ok((sym, tail)) = BorrowedSymbol::with_tail(&line[idx..]) {
54 let demangled = sym
55 .demangle(&options)
56 .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
57 write!(out, "{}", demangled)?;
58 line = tail;
59 } else {
60 write!(out, "_Z")?;
61 line = &line[2..];
62 }
63 }
64
65 write!(out, "{}", String::from_utf8_lossy(line))
66 }
67
68 /// Print all the lines from the given `input` to `out`, with all mangled C++
69 /// symbols replaced with their demangled form.
demangle_all<R, W>(input: &mut R, out: &mut W, options: DemangleOptions) -> io::Result<()> where R: BufRead, W: Write,70 fn demangle_all<R, W>(input: &mut R, out: &mut W, options: DemangleOptions) -> io::Result<()>
71 where
72 R: BufRead,
73 W: Write,
74 {
75 let mut buf = vec![];
76
77 while input.read_until(b'\n', &mut buf)? > 0 {
78 let nl = buf.ends_with(&[b'\n']);
79 if nl {
80 buf.pop();
81 }
82 demangle_line(out, &buf[..], options)?;
83 if nl {
84 write!(out, "\n")?;
85 }
86 buf.clear();
87 }
88
89 Ok(())
90 }
91
main()92 fn main() {
93 let matches = App::new("cppfilt")
94 .version(crate_version!())
95 .author(crate_authors!())
96 .about("A c++filt clone as an example of how to use the cpp_demangle crate!")
97 .arg(
98 Arg::with_name("noparams")
99 .short("p")
100 .long("no-params")
101 .help("Do not display function arguments"),
102 )
103 .arg(
104 Arg::with_name("mangled_names")
105 .multiple(true)
106 .value_delimiter(" "),
107 )
108 .get_matches();
109
110 let stdin = io::stdin();
111 let mut stdin = stdin.lock();
112
113 let stdout = io::stdout();
114 let mut stdout = stdout.lock();
115
116 let stderr = io::stderr();
117 let mut stderr = stderr.lock();
118
119 let mut options = DemangleOptions::new();
120 if matches.is_present("noparams") {
121 options = options.no_params();
122 }
123 if matches.is_present("noreturntype") {
124 options = options.no_return_type();
125 }
126
127 let demangle_result = if let Some(names) = matches.values_of("mangled_names") {
128 let mut input = Cursor::new(names.fold(String::new(), |mut accumulated, name| {
129 accumulated.push_str(&name);
130 accumulated.push_str("\n");
131 accumulated
132 }));
133 demangle_all(&mut input, &mut stdout, options)
134 } else {
135 demangle_all(&mut stdin, &mut stdout, options)
136 };
137
138 let code = match demangle_result {
139 Ok(_) => 0,
140 Err(e) => {
141 let _ = writeln!(&mut stderr, "error: {}", e);
142 1
143 }
144 };
145
146 process::exit(code);
147 }
148