Skip to content

Commit e31d1bb

Browse files
authored
ref: Introduce explicit NameMangling and better DemangleOptions (#275)
1 parent b2d4794 commit e31d1bb

File tree

22 files changed

+404
-298
lines changed

22 files changed

+404
-298
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
- `Unreal4ContextRuntimeProperties::misc_primary_cpu_brand` is has been removed.
1515
- Deprecated Python APIs have been removed:
1616
- `CodeModule.id` and `CodeModule.name` Use `debug_id` and `code_file`, respectively.
17+
- `DemangleFormat` and public fields of `DemangleOptions` have been removed in favor of builder methods on `DemangleOptions`.
18+
- `Name::new` now takes both the `NameMangling` state, and the `Language` explicitly.
1719

1820
## 7.5.0
1921

examples/addr2line/src/main.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ use std::borrow::Borrow;
33
use anyhow::{Context, Result};
44
use clap::{clap_app, ArgMatches};
55

6-
use symbolic::common::{ByteView, Name};
6+
use symbolic::common::{ByteView, Language, Name, NameMangling};
77
use symbolic::debuginfo::{Function, Object};
8-
use symbolic::demangle::Demangle;
8+
use symbolic::demangle::{Demangle, DemangleOptions};
99

1010
fn print_name<'a, N: Borrow<Name<'a>>>(name: Option<N>, matches: &ArgMatches<'_>) {
1111
match name.as_ref().map(Borrow::borrow) {
1212
None => print!("??"),
1313
Some(name) if name.as_str().is_empty() => print!("??"),
1414
Some(name) if matches.is_present("demangle") => {
15-
print!("{}", name.try_demangle(Default::default()));
15+
print!("{}", name.try_demangle(DemangleOptions::name_only()));
1616
}
1717
Some(name) => print!("{}", name),
1818
}
@@ -92,7 +92,13 @@ fn execute(matches: &ArgMatches<'_>) -> Result<()> {
9292

9393
if matches.is_present("functions") {
9494
if let Some(symbol) = symbol_map.lookup(addr) {
95-
print_name(symbol.name.as_ref().map(|n| Name::new(n.as_ref())), matches);
95+
print_name(
96+
symbol
97+
.name
98+
.as_ref()
99+
.map(|n| Name::new(n.as_ref(), NameMangling::Mangled, Language::Unknown)),
100+
matches,
101+
);
96102
print_range(symbol.address, Some(symbol.size), matches);
97103
print!("\n at ");
98104
}

examples/minidump_stackwalk/src/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use walkdir::WalkDir;
77

88
use symbolic::common::{Arch, ByteView, InstructionInfo, SelfCell};
99
use symbolic::debuginfo::{Archive, FileFormat, Object};
10-
use symbolic::demangle::Demangle;
10+
use symbolic::demangle::{Demangle, DemangleOptions};
1111
use symbolic::minidump::cfi::CfiCache;
1212
use symbolic::minidump::processor::{CodeModuleId, FrameInfoMap, ProcessState, StackFrame};
1313
use symbolic::symcache::{LineInfo, SymCache, SymCacheError, SymCacheWriter};
@@ -204,7 +204,8 @@ fn print_state(
204204
"{:>3} {}!{} [{} : {} + 0x{:x}]",
205205
index,
206206
module.debug_file(),
207-
info.function_name().try_demangle(Default::default()),
207+
info.function_name()
208+
.try_demangle(DemangleOptions::name_only()),
208209
info.filename(),
209210
info.line(),
210211
info.instruction_address() - info.line_address(),

examples/symcache_debug/src/main.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ use anyhow::{anyhow, Result};
77
use clap::{App, Arg, ArgMatches};
88

99
use symbolic::common::{Arch, ByteView, DSymPathExt, Language};
10-
use symbolic::debuginfo::Archive;
1110
use symbolic::demangle::Demangle;
1211
use symbolic::symcache::{SymCache, SymCacheWriter};
12+
use symbolic::{debuginfo::Archive, demangle::DemangleOptions};
1313

1414
fn execute(matches: &ArgMatches) -> Result<()> {
1515
let buffer;
@@ -95,7 +95,11 @@ fn execute(matches: &ArgMatches) -> Result<()> {
9595
println!("No match :(");
9696
} else {
9797
for sym in m {
98-
print!("{}", sym.function_name().try_demangle(Default::default()));
98+
print!(
99+
"{}",
100+
sym.function_name()
101+
.try_demangle(DemangleOptions::name_only())
102+
);
99103

100104
let path = sym.path();
101105
let line = sym.line();

py/tests/test_demangle.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33

44
def test_swift_demangle():
55
mangled = "_TFC12Swift_Tester14ViewController11doSomethingfS0_FT_T_"
6-
expected = "ViewController.doSomething(_:)"
6+
expected = "ViewController.doSomething(ViewController)"
77
assert demangle_name(mangled, lang="Swift") == expected
88

99

1010
def test_swift_demangle_implicit():
1111
mangled = "_TFC12Swift_Tester14ViewController11doSomethingfS0_FT_T_"
12-
expected = "ViewController.doSomething(_:)"
12+
expected = "ViewController.doSomething(ViewController)"
1313
assert demangle_name(mangled) == expected
1414

1515

@@ -21,7 +21,7 @@ def test_swift_demangle_options():
2121
)
2222
simplified_expected = (
2323
u"protocol witness for static _ObjectiveCBridgeable._"
24-
u"unconditionallyBridgeFromObjectiveC(_:) "
24+
u"unconditionallyBridgeFromObjectiveC(A._ObjectiveCType?) "
2525
u"in conformance UIApplicationLaunchOptionsKey"
2626
)
2727
assert demangle_name(mangled) == simplified_expected

symbolic-cabi/src/demangle.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
use symbolic::common::Name;
2-
use symbolic::demangle::{Demangle, DemangleFormat, DemangleOptions};
1+
use symbolic::common::{Name, NameMangling};
2+
use symbolic::demangle::{Demangle, DemangleOptions};
33

44
use crate::core::SymbolicStr;
55

66
/// Creates a name from a string passed via FFI.
77
unsafe fn get_name(ident: *const SymbolicStr, lang: *const SymbolicStr) -> Name<'static> {
88
if lang.is_null() {
9-
Name::new((*ident).as_str())
9+
Name::from((*ident).as_str())
1010
} else {
1111
let lang = (*lang).as_str().parse().unwrap_or_default();
12-
Name::with_language((*ident).as_str(), lang)
12+
Name::new((*ident).as_str(), NameMangling::Unknown, lang)
1313
}
1414
}
1515

@@ -23,10 +23,7 @@ ffi_fn! {
2323
lang: *const SymbolicStr,
2424
) -> Result<SymbolicStr> {
2525
let name = get_name(ident, lang);
26-
let demangled = name.try_demangle(DemangleOptions {
27-
with_arguments: true,
28-
format: DemangleFormat::Short,
29-
});
26+
let demangled = name.try_demangle(DemangleOptions::name_only().parameters(true));
3027

3128
Ok(demangled.into_owned().into())
3229
}
@@ -43,10 +40,7 @@ ffi_fn! {
4340
lang: *const SymbolicStr,
4441
) -> Result<SymbolicStr> {
4542
let name = get_name(ident, lang);
46-
let demangled = name.try_demangle(DemangleOptions {
47-
with_arguments: false,
48-
format: DemangleFormat::Short,
49-
});
43+
let demangled = name.try_demangle(DemangleOptions::name_only());
5044

5145
Ok(demangled.into_owned().into())
5246
}

symbolic-common/src/types.rs

Lines changed: 77 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,31 @@ impl str::FromStr for Language {
636636
}
637637
}
638638

639+
/// A [`Name`]s mangling state.
640+
///
641+
/// By default, the mangling of a [`Name`] is not known, but an explicit mangling state can be set
642+
/// for Names that are guaranteed to be unmangled.
643+
#[cfg_attr(
644+
feature = "serde",
645+
derive(Serialize, Deserialize),
646+
serde(crate = "serde_")
647+
)]
648+
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
649+
pub enum NameMangling {
650+
/// The [`Name`] is definitely mangled.
651+
Mangled,
652+
/// The [`Name`] is not mangled.
653+
Unmangled,
654+
/// The mangling of the [`Name`] is not known.
655+
Unknown,
656+
}
657+
658+
impl Default for NameMangling {
659+
fn default() -> Self {
660+
NameMangling::Unknown
661+
}
662+
}
663+
639664
/// The name of a potentially mangled symbol.
640665
///
641666
/// Debugging information often only contains mangled names in their symbol and debug information
@@ -656,16 +681,17 @@ impl str::FromStr for Language {
656681
/// ```
657682
/// use symbolic_common::Name;
658683
///
659-
/// let name = Name::new("_ZN3foo3barEv");
684+
/// let name = Name::from("_ZN3foo3barEv");
660685
/// assert_eq!(name.to_string(), "_ZN3foo3barEv");
661686
/// ```
662687
///
663-
/// Create a name with a language. Alternate formatting prints the language:
688+
/// Create a name with a language and explicit mangling state.
689+
/// Alternate formatting prints the language:
664690
///
665691
/// ```
666-
/// use symbolic_common::{Language, Name};
692+
/// use symbolic_common::{Language, Name, NameMangling};
667693
///
668-
/// let name = Name::with_language("_ZN3foo3barEv", Language::Cpp);
694+
/// let name = Name::new("_ZN3foo3barEv", NameMangling::Mangled, Language::Cpp);
669695
/// assert_eq!(format!("{:#}", name), "_ZN3foo3barEv [C++]");
670696
/// ```
671697
///
@@ -679,52 +705,34 @@ impl str::FromStr for Language {
679705
pub struct Name<'a> {
680706
string: Cow<'a, str>,
681707
lang: Language,
708+
#[cfg_attr(feature = "serde", serde(default))]
709+
mangling: NameMangling,
682710
}
683711

684712
impl<'a> Name<'a> {
685-
/// Constructs a new mangled name.
686-
///
687-
/// The language of this name is `Language::Unknown`.
713+
/// Constructs a new Name with given mangling and language.
688714
///
689-
/// # Example
715+
/// In case both the mangling state and the language are unknown, a simpler alternative to use
716+
/// is [`Name::from`].
690717
///
691-
/// ```
692-
/// use symbolic_common::Name;
693-
///
694-
/// let name = Name::new("_ZN3foo3barEv");
695-
/// assert_eq!(name.to_string(), "_ZN3foo3barEv");
696-
/// ```
697-
#[inline]
698-
pub fn new<S>(string: S) -> Self
699-
where
700-
S: Into<Cow<'a, str>>,
701-
{
702-
Name {
703-
string: string.into(),
704-
lang: Language::Unknown,
705-
}
706-
}
707-
708-
/// Constructs a new mangled name with a known [`Language`].
709718
///
710719
/// # Example
711720
///
712721
/// ```
713-
/// use symbolic_common::{Language, Name};
722+
/// use symbolic_common::{Language, Name, NameMangling};
714723
///
715-
/// let name = Name::with_language("_ZN3foo3barEv", Language::Cpp);
724+
/// let name = Name::new("_ZN3foo3barEv", NameMangling::Mangled, Language::Cpp);
716725
/// assert_eq!(format!("{:#}", name), "_ZN3foo3barEv [C++]");
717726
/// ```
718-
///
719-
/// [`Language`]: enum.Language.html
720727
#[inline]
721-
pub fn with_language<S>(string: S, lang: Language) -> Self
728+
pub fn new<S>(string: S, mangling: NameMangling, lang: Language) -> Self
722729
where
723730
S: Into<Cow<'a, str>>,
724731
{
725732
Name {
726733
string: string.into(),
727734
lang,
735+
mangling,
728736
}
729737
}
730738

@@ -733,24 +741,30 @@ impl<'a> Name<'a> {
733741
/// # Example
734742
///
735743
/// ```
736-
/// use symbolic_common::Name;
744+
/// use symbolic_common::{Language, Name, NameMangling};
737745
///
738-
/// let name = Name::new("_ZN3foo3barEv");
746+
/// let name = Name::new("_ZN3foo3barEv", NameMangling::Mangled, Language::Cpp);
739747
/// assert_eq!(name.as_str(), "_ZN3foo3barEv");
740748
/// ```
741749
///
742750
/// This is also available as an `AsRef<str>` implementation:
743751
///
744752
/// ```
745-
/// use symbolic_common::Name;
753+
/// use symbolic_common::{Language, Name, NameMangling};
746754
///
747-
/// let name = Name::new("_ZN3foo3barEv");
755+
/// let name = Name::new("_ZN3foo3barEv", NameMangling::Mangled, Language::Cpp);
748756
/// assert_eq!(name.as_ref(), "_ZN3foo3barEv");
749757
/// ```
750758
pub fn as_str(&self) -> &str {
751759
&self.string
752760
}
753761

762+
/// Set the `Name`'s language.
763+
pub fn set_language(&mut self, language: Language) -> &mut Self {
764+
self.lang = language;
765+
self
766+
}
767+
754768
/// The language of the mangled symbol.
755769
///
756770
/// If the language is not declared in the source, this returns `Language::Unknown`. The
@@ -760,37 +774,57 @@ impl<'a> Name<'a> {
760774
/// # Example
761775
///
762776
/// ```
763-
/// use symbolic_common::{Language, Name};
777+
/// use symbolic_common::{Language, Name, NameMangling};
764778
///
765-
/// let name = Name::new("_ZN3foo3barEv");
766-
/// assert_eq!(name.language(), Language::Unknown);
779+
/// let name = Name::new("_ZN3foo3barEv", NameMangling::Mangled, Language::Cpp);
780+
/// assert_eq!(name.language(), Language::Cpp);
767781
/// ```
768782
pub fn language(&self) -> Language {
769783
self.lang
770784
}
771785

772-
/// Converts this name into a `Cow`, dropping the language.
786+
/// Set the `Name`'s mangling state.
787+
pub fn set_mangling(&mut self, mangling: NameMangling) -> &mut Self {
788+
self.mangling = mangling;
789+
self
790+
}
791+
792+
/// Returns the `Name`'s mangling state.
793+
///
794+
/// # Example
795+
///
796+
/// ```
797+
/// use symbolic_common::{Language, Name, NameMangling};
798+
///
799+
/// let unmangled = Name::new("foo::bar", NameMangling::Unmangled, Language::Unknown);
800+
/// assert_eq!(unmangled.mangling(), NameMangling::Unmangled);
801+
/// ```
802+
pub fn mangling(&self) -> NameMangling {
803+
self.mangling
804+
}
805+
806+
/// Converts this name into a [`Cow`].
773807
///
774808
/// # Example
775809
///
776810
/// ```
777811
/// use symbolic_common::Name;
778812
///
779-
/// let name = Name::new("_ZN3foo3barEv");
813+
/// let name = Name::from("_ZN3foo3barEv");
780814
/// assert_eq!(name.into_cow(), "_ZN3foo3barEv");
781815
/// ```
782816
pub fn into_cow(self) -> Cow<'a, str> {
783817
self.string
784818
}
785819

786-
/// Converts this name into a `String`, dropping the language.
820+
/// Converts this name into a [`String`].
787821
///
788822
/// # Example
789823
///
790824
/// ```
791825
/// use symbolic_common::Name;
792826
///
793-
/// let name = Name::new("_ZN3foo3barEv");
827+
/// let name = Name::from("_ZN3foo3barEv");
794828
/// assert_eq!(name.into_string(), "_ZN3foo3barEv");
795829
/// ```
796830
pub fn into_string(self) -> String {
@@ -815,7 +849,7 @@ where
815849
S: Into<Cow<'a, str>>,
816850
{
817851
fn from(string: S) -> Self {
818-
Self::new(string)
852+
Self::new(string, NameMangling::Unknown, Language::Unknown)
819853
}
820854
}
821855

symbolic-debuginfo/src/breakpad.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::str;
88
use pest::Parser;
99
use thiserror::Error;
1010

11-
use symbolic_common::{Arch, AsSelf, CodeId, DebugId, Name};
11+
use symbolic_common::{Arch, AsSelf, CodeId, DebugId, Language, Name, NameMangling};
1212

1313
use crate::base::*;
1414
use crate::private::{Lines, Parse};
@@ -1138,7 +1138,7 @@ impl<'s> BreakpadFunctionIterator<'s> {
11381138
Ok(Function {
11391139
address: record.address,
11401140
size: record.size,
1141-
name: Name::from(record.name),
1141+
name: Name::new(record.name, NameMangling::Unmangled, Language::Unknown),
11421142
compilation_dir: &[],
11431143
lines,
11441144
inlinees: Vec::new(),

0 commit comments

Comments
 (0)