@@ -10,6 +10,8 @@ use blazesym::{
10
10
} ;
11
11
use schemars:: JsonSchema ;
12
12
use serde:: { Deserialize , Serialize } ;
13
+ use symbolic_common:: Name ;
14
+ use symbolic_demangle:: { Demangle , DemangleOptions } ;
13
15
14
16
#[ derive( Debug , Clone , PartialEq , Serialize , Deserialize , JsonSchema ) ]
15
17
pub struct StackTrace {
@@ -69,6 +71,18 @@ impl StackTrace {
69
71
self . incomplete = incomplete;
70
72
Ok ( ( ) )
71
73
}
74
+
75
+ pub fn demangle_names ( & mut self ) -> anyhow:: Result < ( ) > {
76
+ let mut errors = 0 ;
77
+ for frame in & mut self . frames {
78
+ frame. demangle_name ( ) . unwrap_or_else ( |e| {
79
+ frame. comments . push ( e. to_string ( ) ) ;
80
+ errors += 1 ;
81
+ } ) ;
82
+ }
83
+ anyhow:: ensure!( errors == 0 ) ;
84
+ Ok ( ( ) )
85
+ }
72
86
}
73
87
74
88
#[ cfg( unix) ]
@@ -137,6 +151,8 @@ pub struct StackFrame {
137
151
pub function : Option < String > ,
138
152
#[ serde( default , skip_serializing_if = "Option::is_none" ) ]
139
153
pub line : Option < u32 > ,
154
+ #[ serde( default , skip_serializing_if = "Option::is_none" ) ]
155
+ pub mangled_name : Option < String > ,
140
156
141
157
// Additional Info
142
158
#[ serde( default , skip_serializing_if = "Vec::is_empty" ) ]
@@ -198,6 +214,23 @@ impl StackFrame {
198
214
}
199
215
}
200
216
217
+ impl StackFrame {
218
+ pub fn demangle_name ( & mut self ) -> anyhow:: Result < ( ) > {
219
+ if let Some ( name) = self . function . take ( ) {
220
+ match Name :: from ( & name) . demangle ( DemangleOptions :: name_only ( ) ) {
221
+ Some ( demangled) if demangled != name => {
222
+ self . mangled_name = Some ( name) ;
223
+ self . function = Some ( demangled. to_string ( ) ) ;
224
+ }
225
+ _ => {
226
+ self . function = Some ( name) ;
227
+ }
228
+ }
229
+ }
230
+ Ok ( ( ) )
231
+ }
232
+ }
233
+
201
234
#[ derive( Debug , Clone , PartialEq , Serialize , Deserialize , JsonSchema ) ]
202
235
#[ allow( clippy:: upper_case_acronyms) ]
203
236
#[ repr( C ) ]
@@ -253,6 +286,7 @@ impl super::test_utils::TestInstance for StackFrame {
253
286
let column = Some ( 2 * seed as u32 ) ;
254
287
let file = Some ( format ! ( "banana{seed}.rs" ) ) ;
255
288
let function = Some ( format ! ( "Bar::baz{seed}" ) ) ;
289
+ let mangled_name = Some ( format ! ( "_ZN3Bar3baz{seed}E" ) ) ;
256
290
let line = Some ( ( 2 * seed + 1 ) as u32 ) ;
257
291
258
292
let comments = vec ! [ format!( "This is a comment on frame {seed}" ) ] ;
@@ -269,8 +303,70 @@ impl super::test_utils::TestInstance for StackFrame {
269
303
column,
270
304
file,
271
305
function,
306
+ mangled_name,
272
307
line,
273
308
comments,
274
309
}
275
310
}
276
311
}
312
+
313
+ #[ cfg( test) ]
314
+ mod tests {
315
+ use super :: * ;
316
+
317
+ #[ test]
318
+ fn test_demangle_rust ( ) {
319
+ let mut frame = StackFrame :: new ( ) ;
320
+ frame. function = Some ( "_ZN3std2rt10lang_start17h7a87e81ecc4a9d6cE" . to_string ( ) ) ;
321
+ frame. demangle_name ( ) . unwrap ( ) ;
322
+ assert_eq ! ( frame. function, Some ( "std::rt::lang_start" . to_string( ) ) ) ;
323
+ assert_eq ! (
324
+ frame. mangled_name,
325
+ Some ( "_ZN3std2rt10lang_start17h7a87e81ecc4a9d6cE" . to_string( ) )
326
+ ) ;
327
+ }
328
+
329
+ #[ test]
330
+ fn test_demangle_cpp ( ) {
331
+ let mut frame = StackFrame :: new ( ) ;
332
+ frame. function = Some ( "_ZN3Foo3barEv" . to_string ( ) ) ;
333
+ frame. demangle_name ( ) . unwrap ( ) ;
334
+ assert_eq ! ( frame. function, Some ( "Foo::bar" . to_string( ) ) ) ;
335
+ assert_eq ! ( frame. mangled_name, Some ( "_ZN3Foo3barEv" . to_string( ) ) ) ;
336
+ }
337
+
338
+ #[ test]
339
+ fn test_demangle_msvc ( ) {
340
+ let mut frame = StackFrame :: new ( ) ;
341
+ frame. function = Some ( "?bar@Foo@@QEAAXXZ" . to_string ( ) ) ;
342
+ frame. demangle_name ( ) . unwrap ( ) ;
343
+ assert_eq ! ( frame. function, Some ( "Foo::bar" . to_string( ) ) ) ;
344
+ assert_eq ! ( frame. mangled_name, Some ( "?bar@Foo@@QEAAXXZ" . to_string( ) ) ) ;
345
+ }
346
+
347
+ #[ test]
348
+ fn test_demangle_unmangled ( ) {
349
+ let mut frame = StackFrame :: new ( ) ;
350
+ frame. function = Some ( "main" . to_string ( ) ) ;
351
+ frame. demangle_name ( ) . unwrap ( ) ;
352
+ assert_eq ! ( frame. function, Some ( "main" . to_string( ) ) ) ;
353
+ assert_eq ! ( frame. mangled_name, None ) ;
354
+ }
355
+
356
+ #[ test]
357
+ fn test_demangle_empty ( ) {
358
+ let mut frame = StackFrame :: new ( ) ;
359
+ frame. demangle_name ( ) . unwrap ( ) ;
360
+ assert_eq ! ( frame. function, None ) ;
361
+ assert_eq ! ( frame. mangled_name, None ) ;
362
+ }
363
+
364
+ #[ test]
365
+ fn test_demangle_invalid ( ) {
366
+ let mut frame = StackFrame :: new ( ) ;
367
+ frame. function = Some ( "invalid_mangled_name" . to_string ( ) ) ;
368
+ frame. demangle_name ( ) . unwrap ( ) ;
369
+ assert_eq ! ( frame. function, Some ( "invalid_mangled_name" . to_string( ) ) ) ;
370
+ assert_eq ! ( frame. mangled_name, None ) ;
371
+ }
372
+ }
0 commit comments