gnuv2_demangle/demangle_config.rs
1/* SPDX-FileCopyrightText: © 2025 Decompollaborate */
2/* SPDX-License-Identifier: MIT OR Apache-2.0 */
3
4/// Tweak how a symbol should be disassembled.
5///
6/// The constructors provide sensible defaults, so there's usually no need to
7/// override each option.
8///
9/// Refer to each option to see what it does and examples.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11#[non_exhaustive]
12pub struct DemangleConfig {
13 /// Recreate a c++filt bug where it won't emit the
14 /// "global constructors keyed to " prefix for a namespaced function.
15 ///
16 /// This is just another c++filt compatibility setting.
17 ///
18 /// # Examples
19 ///
20 /// Turning off this setting (mimicking c++filt behavior):
21 ///
22 /// ```
23 /// use gnuv2_demangle::{demangle, DemangleConfig};
24 ///
25 /// let mut config = DemangleConfig::new();
26 /// config.fix_namespaced_global_constructor_bug = false;
27 ///
28 /// let demangled = demangle("_GLOBAL_$I$__Q210Scenegraph10Scenegraph", &config);
29 /// assert_eq!(
30 /// demangled.as_deref(),
31 /// Ok("Scenegraph::Scenegraph::Scenegraph(void)")
32 /// );
33 /// ```
34 ///
35 /// The setting turned on:
36 ///
37 /// ```
38 /// use gnuv2_demangle::{demangle, DemangleConfig};
39 ///
40 /// let mut config = DemangleConfig::new();
41 /// config.fix_namespaced_global_constructor_bug = true;
42 ///
43 /// let demangled = demangle("_GLOBAL_$I$__Q210Scenegraph10Scenegraph", &config);
44 /// assert_eq!(
45 /// demangled.as_deref(),
46 /// Ok("global constructors keyed to Scenegraph::Scenegraph::Scenegraph(void)")
47 /// );
48 pub fix_namespaced_global_constructor_bug: bool,
49
50 /// By default g++ subtracts 1 from the length of array arguments, thus
51 /// producing a confusing mangled name.
52 ///
53 /// c++filt uses this length as-is, which produces a demangled symbol that
54 /// does not match the original C++ symbol.
55 ///
56 /// This setting adds 1 to the length, making the demangled symbol match
57 /// more accurately the real symbol.
58 ///
59 /// This is just another c++filt compatibility setting.
60 ///
61 /// # Examples
62 ///
63 /// Turning off this setting (mimicking c++filt behavior):
64 ///
65 /// ```
66 /// use gnuv2_demangle::{demangle, DemangleConfig};
67 ///
68 /// let mut config = DemangleConfig::new();
69 /// config.fix_array_length_arg = false;
70 ///
71 /// let demangled = demangle("simpler_array__FPA41_A24_Ci", &config);
72 /// assert_eq!(
73 /// demangled.as_deref(),
74 /// Ok("simpler_array(int const (*)[41][24])")
75 /// );
76 /// ```
77 ///
78 /// The setting turned on:
79 ///
80 /// ```
81 /// use gnuv2_demangle::{demangle, DemangleConfig};
82 ///
83 /// let mut config = DemangleConfig::new();
84 /// config.fix_array_length_arg = true;
85 ///
86 /// let demangled = demangle("simpler_array__FPA41_A24_Ci", &config);
87 /// assert_eq!(
88 /// demangled.as_deref(),
89 /// Ok("simpler_array(int const (*)[42][25])")
90 /// );
91 /// ```
92 pub fix_array_length_arg: bool,
93
94 /// Recognize and demangle symbols prefixed by `_GLOBAL_$F$`.
95 ///
96 /// c++filt does not recognizes this prefix, so it tries to demangle it as
97 /// other mangled kinds, like functions, methods, etc.
98 ///
99 /// When turned on, the symbol gets demangled the same way `_GLOBAL_$I$`
100 /// and `_GLOBAL_$D$` are demangled, but the word "frames" is used instead
101 /// of "constructors" or "destructors". This name is made-up based on some
102 /// usages from projects that have this symbol present.
103 ///
104 /// This is just another c++filt compatibility setting.
105 ///
106 /// # Examples
107 ///
108 /// Turning off this setting (mimicking c++filt behavior):
109 ///
110 /// ```
111 /// use gnuv2_demangle::{demangle, DemangleConfig};
112 ///
113 /// let mut config = DemangleConfig::new();
114 /// config.demangle_global_keyed_frames = false;
115 ///
116 /// let demangled = demangle("_GLOBAL_$F$__7istreamiP9streambufP7ostream", &config);
117 /// assert_eq!(
118 /// demangled.as_deref(),
119 /// Ok("istream::_GLOBAL_$F$(int, streambuf *, ostream *)")
120 /// );
121 /// let demangled = demangle("_GLOBAL_$F$__default_terminate", &config);
122 /// assert!(
123 /// demangled.is_err()
124 /// );
125 /// ```
126 ///
127 /// The setting turned on:
128 ///
129 /// ```
130 /// use gnuv2_demangle::{demangle, DemangleConfig};
131 ///
132 /// let mut config = DemangleConfig::new();
133 /// config.demangle_global_keyed_frames = true;
134 ///
135 /// let demangled = demangle("_GLOBAL_$F$__7istreamiP9streambufP7ostream", &config);
136 /// assert_eq!(
137 /// demangled.as_deref(),
138 /// Ok("global frames keyed to istream::istream(int, streambuf *, ostream *)")
139 /// );
140 /// let demangled = demangle("_GLOBAL_$F$__default_terminate", &config);
141 /// assert_eq!(
142 /// demangled.as_deref(),
143 /// Ok("global frames keyed to __default_terminate")
144 /// );
145 /// ```
146 pub demangle_global_keyed_frames: bool,
147
148 /// Emit an space between a comma and an ellipsis (`...`) in the argument
149 /// list.
150 ///
151 /// This is just another c++filt compatibility setting.
152 ///
153 /// # Examples
154 ///
155 /// Turning off this setting (mimicking c++filt behavior):
156 ///
157 /// ```
158 /// use gnuv2_demangle::{demangle, DemangleConfig};
159 ///
160 /// let mut config = DemangleConfig::new();
161 /// config.ellipsis_emit_space_after_comma = false;
162 ///
163 /// let demangled = demangle("Printf__7ConsolePce", &config);
164 /// assert_eq!(
165 /// demangled.as_deref(),
166 /// Ok("Console::Printf(char *,...)")
167 /// );
168 /// ```
169 ///
170 /// The setting turned on:
171 ///
172 /// ```
173 /// use gnuv2_demangle::{demangle, DemangleConfig};
174 ///
175 /// let mut config = DemangleConfig::new();
176 /// config.ellipsis_emit_space_after_comma = true;
177 ///
178 /// let demangled = demangle("Printf__7ConsolePce", &config);
179 /// assert_eq!(
180 /// demangled.as_deref(),
181 /// Ok("Console::Printf(char *, ...)")
182 /// );
183 /// ```
184 pub ellipsis_emit_space_after_comma: bool,
185
186 /// If enabled, emit `__int128_t` and `__uint128_t` types instead of
187 /// `int128_t` and `unsigned int128_t`.
188 ///
189 /// The former is valid syntax in g++ for this GNU integer extension type,
190 /// while the latter is the syntax used by c++filt, but not accepted by g++.
191 ///
192 /// This is just another c++filt compatibility setting.
193 ///
194 /// # Examples
195 ///
196 /// Turning off this setting (mimicking c++filt behavior):
197 ///
198 /// ```
199 /// use gnuv2_demangle::{demangle, DemangleConfig};
200 ///
201 /// let mut config = DemangleConfig::new();
202 /// config.fix_extension_int = false;
203 ///
204 /// let demangled = demangle("testing_func__FRCI80", &config);
205 /// assert_eq!(
206 /// demangled.as_deref(),
207 /// Ok("testing_func(int128_t const &)")
208 /// );
209 /// let demangled = demangle("testing_func__FRCUI80", &config);
210 /// assert_eq!(
211 /// demangled.as_deref(),
212 /// Ok("testing_func(unsigned int128_t const &)")
213 /// );
214 /// ```
215 ///
216 /// The setting turned on:
217 ///
218 /// ```
219 /// use gnuv2_demangle::{demangle, DemangleConfig};
220 ///
221 /// let mut config = DemangleConfig::new();
222 /// config.fix_extension_int = true;
223 ///
224 /// let demangled = demangle("testing_func__FRCI80", &config);
225 /// assert_eq!(
226 /// demangled.as_deref(),
227 /// Ok("testing_func(__int128_t const &)")
228 /// );
229 /// let demangled = demangle("testing_func__FRCUI80", &config);
230 /// assert_eq!(
231 /// demangled.as_deref(),
232 /// Ok("testing_func(__uint128_t const &)")
233 /// );
234 /// ```
235 pub fix_extension_int: bool,
236
237 /// If enabled, emit proper syntax for arrays as return types in templated
238 /// functions.
239 ///
240 /// Disabling this option make it mimic the c++filt behavior for arrays in
241 /// return position, which is not valid C++ but is simpler to read.
242 ///
243 /// # Examples
244 ///
245 /// Turning off this setting (mimicking c++filt behavior):
246 ///
247 /// ```
248 /// use gnuv2_demangle::{demangle, DemangleConfig};
249 ///
250 /// let mut config = DemangleConfig::new();
251 /// config.fix_array_in_return_position = false;
252 ///
253 /// let demangled = demangle("an_array__H1Zi_X01_PA3_f", &config);
254 /// assert_eq!(
255 /// demangled.as_deref(),
256 /// Ok("float (*)[3] an_array<int>(int)")
257 /// );
258 /// ```
259 ///
260 /// The setting turned on:
261 ///
262 /// ```
263 /// use gnuv2_demangle::{demangle, DemangleConfig};
264 ///
265 /// let mut config = DemangleConfig::new();
266 /// config.fix_array_in_return_position = true;
267 ///
268 /// let demangled = demangle("an_array__H1Zi_X01_PA3_f", &config);
269 /// assert_eq!(
270 /// demangled.as_deref(),
271 /// Ok("float (*an_array<int>(int))[3]")
272 /// );
273 /// ```
274 pub fix_array_in_return_position: bool,
275}
276
277impl DemangleConfig {
278 /// The default configuration.
279 pub const fn new() -> Self {
280 Self::new_g2dem()
281 }
282
283 /// Use improved output and valid C++ syntax whenever possible.
284 pub const fn new_g2dem() -> Self {
285 Self {
286 fix_namespaced_global_constructor_bug: true,
287 fix_array_length_arg: true,
288 demangle_global_keyed_frames: true,
289 ellipsis_emit_space_after_comma: true,
290 fix_extension_int: true,
291 fix_array_in_return_position: true,
292 }
293 }
294
295 /// Mimics the (rather questionable) c++filt's behavior, including what may
296 /// be considered c++filt bugs.
297 ///
298 /// Useful for validating demangling against c++filt.
299 pub const fn new_cfilt() -> Self {
300 Self {
301 fix_namespaced_global_constructor_bug: false,
302 fix_array_length_arg: false,
303 demangle_global_keyed_frames: false,
304 ellipsis_emit_space_after_comma: false,
305 fix_extension_int: false,
306 fix_array_in_return_position: false,
307 }
308 }
309}
310
311impl Default for DemangleConfig {
312 fn default() -> Self {
313 Self::new()
314 }
315}