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}