symbolic-demangle-12.4.0/Cargo.toml0000644000000030110000000000100125040ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "symbolic-demangle" version = "12.4.0" authors = [ "Armin Ronacher ", "Jan Michael Auer ", ] build = "build.rs" exclude = ["tests/**/*"] description = """ A library to demangle symbols from various languages and compilers. """ homepage = "https://github.com/getsentry/symbolic" documentation = "https://docs.rs/symbolic-demangle" readme = "README.md" license = "MIT" repository = "https://github.com/getsentry/symbolic" [package.metadata.docs.rs] all-features = true [dependencies.cpp_demangle] version = "0.4.1" optional = true [dependencies.msvc-demangler] version = "0.9.0" optional = true [dependencies.rustc-demangle] version = "0.1.21" optional = true [dependencies.symbolic-common] version = "12.4.0" [dev-dependencies.similar-asserts] version = "1.4.2" [build-dependencies.cc] version = "1.0.79" optional = true [features] cpp = ["cpp_demangle"] default = [ "cpp", "msvc", "rust", "swift", ] msvc = ["msvc-demangler"] rust = ["rustc-demangle"] swift = ["cc"] symbolic-demangle-12.4.0/Cargo.toml.orig000064400000000000000000000020621046102023000161720ustar 00000000000000[package] name = "symbolic-demangle" version = "12.4.0" license = "MIT" authors = [ "Armin Ronacher ", "Jan Michael Auer ", ] documentation = "https://docs.rs/symbolic-demangle" homepage = "https://github.com/getsentry/symbolic" repository = "https://github.com/getsentry/symbolic" readme = "README.md" description = """ A library to demangle symbols from various languages and compilers. """ build = "build.rs" edition = "2021" exclude = [ "tests/**/*", ] [package.metadata.docs.rs] all-features = true [features] default = ["cpp", "msvc", "rust", "swift"] cpp = ["cpp_demangle"] msvc = ["msvc-demangler"] rust = ["rustc-demangle"] swift = ["cc"] [dependencies] cpp_demangle = { version = "0.4.1", optional = true } msvc-demangler = { version = "0.9.0", optional = true } rustc-demangle = { version = "0.1.21", optional = true } symbolic-common = { version = "12.4.0", path = "../symbolic-common" } [build-dependencies] cc = { version = "1.0.79", optional = true } [dev-dependencies] similar-asserts = "1.4.2" symbolic-demangle-12.4.0/README.md000064400000000000000000000020031046102023000145550ustar 00000000000000[![Build Status](https://travis-ci.org/getsentry/symbolic.svg?branch=master)](https://travis-ci.org/getsentry/symbolic) # symbolic-demangle Demangling support for various languages and compilers. Currently supported languages are: - C++ (GCC-style compilers and MSVC) - Rust (both `legacy` and `v0`) - Swift (up to Swift 5.2) - ObjC (only symbol detection) As the demangling schemes for the languages are different, the supported demangling features are inconsistent. For example, argument types were not encoded in legacy Rust mangling and thus not available in demangled names. This module is part of the `symbolic` crate and can be enabled via the `demangle` feature. ## Examples ```rust use symbolic::common::{Language, Name}; use symbolic::demangle::{Demangle, DemangleOptions}; let name = Name::new("__ZN3std2io4Read11read_to_end17hb85a0f6802e14499E"); assert_eq!(name.detect_language(), Language::Rust); assert_eq!(name.try_demangle(DemangleOptions::default()), "std::io::Read::read_to_end"); ``` License: MIT symbolic-demangle-12.4.0/build.rs000064400000000000000000000017121046102023000147510ustar 00000000000000fn main() { #[cfg(feature = "swift")] { cc::Build::new() .cpp(true) .files(&[ "src/swiftdemangle.cpp", "vendor/swift/lib/Demangling/Demangler.cpp", "vendor/swift/lib/Demangling/Context.cpp", "vendor/swift/lib/Demangling/ManglingUtils.cpp", "vendor/swift/lib/Demangling/NodeDumper.cpp", "vendor/swift/lib/Demangling/NodePrinter.cpp", "vendor/swift/lib/Demangling/OldDemangler.cpp", // "vendor/swift/lib/Demangling/OldRemangler.cpp", "vendor/swift/lib/Demangling/Punycode.cpp", "vendor/swift/lib/Demangling/Remangler.cpp", ]) .flag_if_supported("-std=c++14") .flag("-DLLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING=1") .warnings(false) .include("vendor/swift/include") .compile("swiftdemangle"); } } symbolic-demangle-12.4.0/src/lib.rs000064400000000000000000000377721046102023000152260ustar 00000000000000//! Demangling support for various languages and compilers. //! //! Currently supported languages are: //! //! - C++ (GCC-style compilers and MSVC) (`features = ["cpp", "msvc"]`) //! - Rust (both `legacy` and `v0`) (`features = ["rust"]`) //! - Swift (up to Swift 5.3) (`features = ["swift"]`) //! - ObjC (only symbol detection) //! //! As the demangling schemes for the languages are different, the supported demangling features are //! inconsistent. For example, argument types were not encoded in legacy Rust mangling and thus not //! available in demangled names. //! The demangling results should not be considered stable, and may change over time as more //! demangling features are added. //! //! This module is part of the `symbolic` crate and can be enabled via the `demangle` feature. //! //! # Examples //! //! ```rust //! # #[cfg(feature = "rust")] { //! use symbolic_common::{Language, Name}; //! use symbolic_demangle::{Demangle, DemangleOptions}; //! //! let name = Name::from("__ZN3std2io4Read11read_to_end17hb85a0f6802e14499E"); //! assert_eq!(name.detect_language(), Language::Rust); //! assert_eq!( //! name.try_demangle(DemangleOptions::complete()), //! "std::io::Read::read_to_end" //! ); //! # } //! ``` #![warn(missing_docs)] use std::borrow::Cow; #[cfg(feature = "swift")] use std::ffi::{CStr, CString}; #[cfg(feature = "swift")] use std::os::raw::{c_char, c_int}; use symbolic_common::{Language, Name, NameMangling}; #[cfg(feature = "swift")] const SYMBOLIC_SWIFT_FEATURE_RETURN_TYPE: c_int = 0x1; #[cfg(feature = "swift")] const SYMBOLIC_SWIFT_FEATURE_PARAMETERS: c_int = 0x2; #[cfg(feature = "swift")] extern "C" { fn symbolic_demangle_swift( sym: *const c_char, buf: *mut c_char, buf_len: usize, features: c_int, ) -> c_int; fn symbolic_demangle_is_swift_symbol(sym: *const c_char) -> c_int; } /// Options for [`Demangle::demangle`]. /// /// One can chose from complete, or name-only demangling, and toggle specific demangling features /// explicitly. /// /// The resulting output depends very much on the language of the mangled [`Name`], and may change /// over time as more fine grained demangling options and features are added. Not all options are /// fully supported by each language, and not every feature is mutually exclusive on all languages. /// /// # Examples /// /// ``` /// # #[cfg(feature = "swift")] { /// use symbolic_common::{Name, NameMangling, Language}; /// use symbolic_demangle::{Demangle, DemangleOptions}; /// /// let symbol = Name::new("$s8mangling12GenericUnionO3FooyACyxGSicAEmlF", NameMangling::Mangled, Language::Swift); /// /// let simple = symbol.demangle(DemangleOptions::name_only()).unwrap(); /// assert_eq!(&simple, "GenericUnion.Foo"); /// /// let full = symbol.demangle(DemangleOptions::complete()).unwrap(); /// assert_eq!(&full, "mangling.GenericUnion.Foo(mangling.GenericUnion.Type) -> (Swift.Int) -> mangling.GenericUnion"); /// # } /// ``` /// /// [`Demangle::demangle`]: trait.Demangle.html#tymethod.demangle #[derive(Clone, Copy, Debug)] pub struct DemangleOptions { return_type: bool, parameters: bool, } impl DemangleOptions { /// DemangleOptions that output a complete verbose demangling. pub const fn complete() -> Self { Self { return_type: true, parameters: true, } } /// DemangleOptions that output the most simple (likely name-only) demangling. pub const fn name_only() -> Self { Self { return_type: false, parameters: false, } } /// Determines whether a functions return type should be demangled. pub const fn return_type(mut self, return_type: bool) -> Self { self.return_type = return_type; self } /// Determines whether function argument types should be demangled. pub const fn parameters(mut self, parameters: bool) -> Self { self.parameters = parameters; self } } fn is_maybe_objc(ident: &str) -> bool { (ident.starts_with("-[") || ident.starts_with("+[")) && ident.ends_with(']') } fn is_maybe_cpp(ident: &str) -> bool { ident.starts_with("_Z") || ident.starts_with("__Z") || ident.starts_with("___Z") || ident.starts_with("____Z") } fn is_maybe_msvc(ident: &str) -> bool { ident.starts_with('?') || ident.starts_with("@?") } /// An MD5 mangled name consists of the prefix "??@", 32 hex digits, /// and the suffix "@". fn is_maybe_md5(ident: &str) -> bool { if ident.len() != 36 { return false; } ident.starts_with("??@") && ident.ends_with('@') && ident[3..35].chars().all(|c| c.is_ascii_hexdigit()) } #[cfg(feature = "swift")] fn is_maybe_swift(ident: &str) -> bool { CString::new(ident) .map(|cstr| unsafe { symbolic_demangle_is_swift_symbol(cstr.as_ptr()) != 0 }) .unwrap_or(false) } #[cfg(not(feature = "swift"))] fn is_maybe_swift(_ident: &str) -> bool { false } #[cfg(feature = "msvc")] fn try_demangle_msvc(ident: &str, opts: DemangleOptions) -> Option { use msvc_demangler::DemangleFlags as MsvcFlags; // the flags are bitflags let mut flags = MsvcFlags::COMPLETE | MsvcFlags::SPACE_AFTER_COMMA | MsvcFlags::HUG_TYPE | MsvcFlags::NO_MS_KEYWORDS | MsvcFlags::NO_CLASS_TYPE; if !opts.return_type { flags |= MsvcFlags::NO_FUNCTION_RETURNS; } if !opts.parameters { // a `NO_ARGUMENTS` flag is there in the code, but commented out flags |= MsvcFlags::NAME_ONLY; } msvc_demangler::demangle(ident, flags).ok() } #[cfg(not(feature = "msvc"))] fn try_demangle_msvc(_ident: &str, _opts: DemangleOptions) -> Option { None } /// Removes a suffix consisting of $ followed by 32 hex digits, if there is one, /// otherwise returns its input. fn strip_hash_suffix(ident: &str) -> &str { let len = ident.len(); if len >= 33 { let mut char_iter = ident.char_indices(); while let Some((pos, c)) = char_iter.next_back() { if (len - pos) == 33 && c == '$' { // If we have not yet returned we have a valid suffix to strip. This is // safe because we know the current pos is on the start of the '$' char // boundary. return &ident[..pos]; } else if (len - pos) > 33 || !c.is_ascii_hexdigit() { // If pos is more than 33 bytes from the end a multibyte char made us skip // pos 33, multibyte chars are not hexdigit or $ so nothing to strip. return ident; } } } ident } struct BoundedString { str: String, bound: usize, } impl BoundedString { fn new(bound: usize) -> Self { Self { str: String::new(), bound, } } pub fn into_inner(self) -> String { self.str } } impl std::fmt::Write for BoundedString { fn write_str(&mut self, s: &str) -> std::fmt::Result { if self.str.len().saturating_add(s.len()) > self.bound { return Err(std::fmt::Error); } self.str.write_str(s) } } fn try_demangle_cpp(ident: &str, opts: DemangleOptions) -> Option { if is_maybe_msvc(ident) { return try_demangle_msvc(ident, opts); } // C++ *symbols* will always start with a `_Z` prefix, but `cpp_demangle` is a bit more lenient // and will also demangle bare types, turning `a` into `signed char` for example. So lets be // a bit stricter and make sure we always have a `_Z` prefix. if !is_maybe_cpp(ident) { return None; } #[cfg(feature = "cpp")] { use cpp_demangle::{DemangleOptions as CppOptions, ParseOptions, Symbol as CppSymbol}; let stripped = strip_hash_suffix(ident); let parse_options = ParseOptions::default().recursion_limit(160); // default is 96 let symbol = match CppSymbol::new_with_options(stripped, &parse_options) { Ok(symbol) => symbol, Err(_) => return None, }; let mut cpp_options = CppOptions::new().recursion_limit(192); // default is 128 if !opts.parameters { cpp_options = cpp_options.no_params(); } if !opts.return_type { cpp_options = cpp_options.no_return_type(); } // Bound the maximum output string, as a huge number of substitutions could potentially // lead to a "Billion laughs attack". let mut buf = BoundedString::new(4096); symbol .structured_demangle(&mut buf, &cpp_options) .ok() .map(|_| buf.into_inner()) } #[cfg(not(feature = "cpp"))] { None } } #[cfg(feature = "rust")] fn try_demangle_rust(ident: &str, _opts: DemangleOptions) -> Option { match rustc_demangle::try_demangle(ident) { Ok(demangled) => Some(format!("{demangled:#}")), Err(_) => None, } } #[cfg(not(feature = "rust"))] fn try_demangle_rust(_ident: &str, _opts: DemangleOptions) -> Option { None } #[cfg(feature = "swift")] fn try_demangle_swift(ident: &str, opts: DemangleOptions) -> Option { let mut buf = vec![0; 4096]; let sym = match CString::new(ident) { Ok(sym) => sym, Err(_) => return None, }; let mut features = 0; if opts.return_type { features |= SYMBOLIC_SWIFT_FEATURE_RETURN_TYPE; } if opts.parameters { features |= SYMBOLIC_SWIFT_FEATURE_PARAMETERS; } unsafe { match symbolic_demangle_swift(sym.as_ptr(), buf.as_mut_ptr(), buf.len(), features) { 0 => None, _ => Some(CStr::from_ptr(buf.as_ptr()).to_string_lossy().to_string()), } } } #[cfg(not(feature = "swift"))] fn try_demangle_swift(_ident: &str, _opts: DemangleOptions) -> Option { None } fn demangle_objc(ident: &str, _opts: DemangleOptions) -> String { ident.to_string() } fn try_demangle_objcpp(ident: &str, opts: DemangleOptions) -> Option { if is_maybe_objc(ident) { Some(demangle_objc(ident, opts)) } else if is_maybe_cpp(ident) { try_demangle_cpp(ident, opts) } else { None } } /// An extension trait on `Name` for demangling names. /// /// See the [module level documentation] for a list of supported languages. /// /// [module level documentation]: index.html pub trait Demangle { /// Infers the language of a mangled name. /// /// In case the symbol is not mangled or its language is unknown, the return value will be /// `Language::Unknown`. If the language of the symbol was specified explicitly, this is /// returned instead. For a list of supported languages, see the [module level documentation]. /// /// # Examples /// /// ``` /// use symbolic_common::{Language, Name}; /// use symbolic_demangle::{Demangle, DemangleOptions}; /// /// assert_eq!(Name::from("_ZN3foo3barEv").detect_language(), Language::Cpp); /// assert_eq!(Name::from("unknown").detect_language(), Language::Unknown); /// ``` /// /// [module level documentation]: index.html fn detect_language(&self) -> Language; /// Demangles the name with the given options. /// /// Returns `None` in one of the following cases: /// 1. The language cannot be detected. /// 2. The language is not supported. /// 3. Demangling of the name failed. /// /// # Examples /// /// ``` /// # #[cfg(feature = "cpp")] { /// use symbolic_common::Name; /// use symbolic_demangle::{Demangle, DemangleOptions}; /// /// assert_eq!( /// Name::from("_ZN3foo3barEv").demangle(DemangleOptions::name_only()), /// Some("foo::bar".to_string()) /// ); /// assert_eq!( /// Name::from("unknown").demangle(DemangleOptions::name_only()), /// None /// ); /// # } /// ``` fn demangle(&self, opts: DemangleOptions) -> Option; /// Tries to demangle the name and falls back to the original name. /// /// Similar to [`demangle`], except that it returns a borrowed instance of the original name if /// the name cannot be demangled. /// /// # Examples /// /// ``` /// # #[cfg(feature = "cpp")] { /// use symbolic_common::Name; /// use symbolic_demangle::{Demangle, DemangleOptions}; /// /// assert_eq!( /// Name::from("_ZN3foo3barEv").try_demangle(DemangleOptions::name_only()), /// "foo::bar" /// ); /// assert_eq!( /// Name::from("unknown").try_demangle(DemangleOptions::name_only()), /// "unknown" /// ); /// # } /// ``` /// /// [`demangle`]: trait.Demangle.html#tymethod.demangle fn try_demangle(&self, opts: DemangleOptions) -> Cow<'_, str>; } impl<'a> Demangle for Name<'a> { fn detect_language(&self) -> Language { if self.language() != Language::Unknown { return self.language(); } if is_maybe_objc(self.as_str()) { return Language::ObjC; } #[cfg(feature = "rust")] { if rustc_demangle::try_demangle(self.as_str()).is_ok() { return Language::Rust; } } if is_maybe_cpp(self.as_str()) || is_maybe_msvc(self.as_str()) { return Language::Cpp; } if is_maybe_swift(self.as_str()) { return Language::Swift; } Language::Unknown } fn demangle(&self, opts: DemangleOptions) -> Option { if matches!(self.mangling(), NameMangling::Unmangled) || is_maybe_md5(self.as_str()) { return Some(self.to_string()); } match self.detect_language() { Language::ObjC => Some(demangle_objc(self.as_str(), opts)), Language::ObjCpp => try_demangle_objcpp(self.as_str(), opts), Language::Rust => try_demangle_rust(self.as_str(), opts), Language::Cpp => try_demangle_cpp(self.as_str(), opts), Language::Swift => try_demangle_swift(self.as_str(), opts), _ => None, } } fn try_demangle(&self, opts: DemangleOptions) -> Cow<'_, str> { if matches!(self.mangling(), NameMangling::Unmangled) { return Cow::Borrowed(self.as_str()); } match self.demangle(opts) { Some(demangled) => Cow::Owned(demangled), None => Cow::Borrowed(self.as_str()), } } } /// Demangles an identifier and falls back to the original symbol. /// /// This is a shortcut for [`Demangle::try_demangle`] with complete demangling. /// /// # Examples /// /// ``` /// # #[cfg(feature = "cpp")] { /// assert_eq!(symbolic_demangle::demangle("_ZN3foo3barEv"), "foo::bar()"); /// # } /// ``` /// /// [`Demangle::try_demangle`]: trait.Demangle.html#tymethod.try_demangle pub fn demangle(ident: &str) -> Cow<'_, str> { match Name::from(ident).demangle(DemangleOptions::complete()) { Some(demangled) => Cow::Owned(demangled), None => Cow::Borrowed(ident), } } #[cfg(test)] mod test { use super::*; use symbolic_common::Name; #[test] fn simple_md5() { let md5_mangled = "??@8ba8d245c9eca390356129098dbe9f73@"; assert_eq!( Name::from(md5_mangled) .demangle(DemangleOptions::name_only()) .unwrap(), md5_mangled ); } #[test] fn test_strip_hash_suffix() { assert_eq!( strip_hash_suffix("hello$0123456789abcdef0123456789abcdef"), "hello" ); assert_eq!( strip_hash_suffix("hello_0123456789abcdef0123456789abcdef"), "hello_0123456789abcdef0123456789abcdef", ); assert_eq!( strip_hash_suffix("hello\u{1000}0123456789abcdef0123456789abcdef"), "hello\u{1000}0123456789abcdef0123456789abcdef" ); assert_eq!( strip_hash_suffix("hello$0123456789abcdef0123456789abcdxx"), "hello$0123456789abcdef0123456789abcdxx" ); assert_eq!( strip_hash_suffix("hello$\u{1000}0123456789abcdef0123456789abcde"), "hello$\u{1000}0123456789abcdef0123456789abcde" ); } } symbolic-demangle-12.4.0/src/swiftdemangle.cpp000064400000000000000000000024061046102023000174310ustar 00000000000000#include "swift/Demangling/Demangle.h" #define SYMBOLIC_SWIFT_FEATURE_RETURN_TYPE 0x1 #define SYMBOLIC_SWIFT_FEATURE_PARAMETERS 0x2 #define SYMBOLIC_SWIFT_FEATURE_ALL 0x3 extern "C" int symbolic_demangle_swift(const char *symbol, char *buffer, size_t buffer_length, int features) { swift::Demangle::DemangleOptions opts; if (features < SYMBOLIC_SWIFT_FEATURE_ALL) { opts = swift::Demangle::DemangleOptions::SimplifiedUIDemangleOptions(); bool return_type = features & SYMBOLIC_SWIFT_FEATURE_RETURN_TYPE; bool argument_types = features & SYMBOLIC_SWIFT_FEATURE_PARAMETERS; opts.ShowFunctionReturnType = return_type; opts.ShowFunctionArgumentTypes = argument_types; } std::string demangled = swift::Demangle::demangleSymbolAsString(llvm::StringRef(symbol), opts); if (demangled.size() == 0 || demangled.size() >= buffer_length) { return false; } memcpy(buffer, demangled.c_str(), demangled.size()); buffer[demangled.size()] = '\0'; return true; } extern "C" int symbolic_demangle_is_swift_symbol(const char *symbol) { return swift::Demangle::isSwiftSymbol(symbol); } symbolic-demangle-12.4.0/vendor/swift/1-arguments.patch000064400000000000000000000034171046102023000211250ustar 00000000000000commit 43fca7dd2617ac93f338b5257a2e57c43dcb8154 Author: Sebastian Zivota Date: Thu Dec 2 16:15:35 2021 +0100 Apply patch diff --git a/symbolic-demangle/vendor/swift/include/swift/Demangling/Demangle.h b/symbolic-demangle/vendor/swift/include/swift/Demangling/Demangle.h index db32dbd..f48e1c2 100644 --- a/symbolic-demangle/vendor/swift/include/swift/Demangling/Demangle.h +++ b/symbolic-demangle/vendor/swift/include/swift/Demangling/Demangle.h @@ -59,6 +59,7 @@ struct DemangleOptions { bool ShortenArchetype = false; bool ShowPrivateDiscriminators = true; bool ShowFunctionArgumentTypes = true; + bool ShowFunctionReturnType = true; bool DisplayDebuggerGeneratedModule = true; bool DisplayStdlibModule = true; bool DisplayObjCModule = true; @@ -90,6 +91,7 @@ struct DemangleOptions { Opt.ShortenArchetype = true; Opt.ShowPrivateDiscriminators = false; Opt.ShowFunctionArgumentTypes = false; + Opt.ShowFunctionReturnType = false; return Opt; }; }; diff --git a/symbolic-demangle/vendor/swift/lib/Demangling/NodePrinter.cpp b/symbolic-demangle/vendor/swift/lib/Demangling/NodePrinter.cpp index 2a9c0dc..34fa785 100644 --- a/symbolic-demangle/vendor/swift/lib/Demangling/NodePrinter.cpp +++ b/symbolic-demangle/vendor/swift/lib/Demangling/NodePrinter.cpp @@ -863,10 +863,11 @@ private: if (isSendable) Printer << "@Sendable "; - printFunctionParameters(LabelList, node->getChild(startIndex), - Options.ShowFunctionArgumentTypes); + if (Options.ShowFunctionArgumentTypes) { + printFunctionParameters(LabelList, node->getChild(startIndex), true); + } - if (!Options.ShowFunctionArgumentTypes) + if (!Options.ShowFunctionReturnType) return; if (isAsync) symbolic-demangle-12.4.0/vendor/swift/LICENSE.txt000064400000000000000000000267471046102023000175770ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ## Runtime Library Exception to the Apache 2.0 License: ## As an exception, if you use this Software to compile your source code and portions of this Software are embedded into the binary product as a result, you may redistribute such product without providing attribution as would otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. symbolic-demangle-12.4.0/vendor/swift/LICENSE_LLVM.txt000064400000000000000000000061701046102023000204150ustar 00000000000000============================================================================== LLVM Release License ============================================================================== University of Illinois/NCSA Open Source License Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign. All rights reserved. Developed by: LLVM Team University of Illinois at Urbana-Champaign http://llvm.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. * Neither the names of the LLVM Team, University of Illinois at Urbana-Champaign, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. ============================================================================== Copyrights and Licenses for Third Party Software Distributed with LLVM: ============================================================================== The LLVM software contains code written by third parties. Such software will have its own individual LICENSE.TXT file in the directory in which it appears. This file will describe the copyrights, license, and restrictions which apply to that code. The disclaimer of warranty in the University of Illinois Open Source License applies to all code in the LLVM Distribution, and nothing in any of the other licenses gives permission to use the names of the LLVM Team or the University of Illinois to endorse or promote products derived from this Software. The following pieces of software have additional or alternate copyrights, licenses, and/or restrictions: Program Directory ------- --------- Google Test llvm/utils/unittest/googletest OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex} pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT} ARM contributions llvm/lib/Target/ARM/LICENSE.TXT md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h symbolic-demangle-12.4.0/vendor/swift/README.md000064400000000000000000000041331046102023000172140ustar 00000000000000# Vendored Swift Demangler This folder contains a vendored subset of the [Swift Programming Language]. The Swift library is reduced to the demangler only to reduce the size of this package. The current version is **Swift 5.5.1**. ## Sentry Modifications The library has been modified to add an option to hide function arguments during demangling. This patch is maintained in `1-arguments.patch`. ## How to Update 1. **Check out the [latest release] of Swift:** 1. Create a directory that will house swift and its dependencies: ``` $ mkdir swift-source && cd swift-source ``` 2. Clone the swift repository into a subdirectory: ``` $ git clone https://github.com/apple/swift.git ``` 3. Check out dependencies: ``` $ ./swift/utils/update-checkout --clone ``` 4. Check out the release branch of the latest release: ``` $ cd swift $ git checkout swift-5.5.1-RELEASE ``` 5. Build the complete swift project (be very patient, this may take long): ``` $ ./utils/build-script --skip-build ``` 2. **Copy updated sources and headers from the checkout to this library:** 1. Run the update script in this directory (requires Python 3): ``` $ ./update.py swift-source ``` 2. Check for modifications. 3. Commit _"feat(demangle): Import libswift demangle x.x.x"_ before proceeding. 3. **Apply the patch:** 1. Apply `1-arguments.patch`. 2. Build the Rust library and ensure tests work. 3. Commit the changes. 4. **Add tests for new mangling schemes:** 1. Identify new mangling schemes. Skip if there are no known changes. 2. Add test cases to `tests/swift.rs` 5. **Update Repository metadata**: 1. Bump the Swift version number in this README. 2. Check for changes in the license and update the files. 3. Update the patch file with the commit generated in step 3: ``` $ git show > 1-arguments.patch ``` 6. **Create a pull request.** [swift programming language]: https://github.com/apple/swift [latest release]: https://github.com/apple/swift/releases/latest/ symbolic-demangle-12.4.0/vendor/swift/include/llvm/ADT/Hashing.h000064400000000000000000000636141046102023000225050ustar 00000000000000//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements the newly proposed standard C++ interfaces for hashing // arbitrary data and building hash functions for user-defined types. This // interface was originally proposed in N3333[1] and is currently under review // for inclusion in a future TR and/or standard. // // The primary interfaces provide are comprised of one type and three functions: // // -- 'hash_code' class is an opaque type representing the hash code for some // data. It is the intended product of hashing, and can be used to implement // hash tables, checksumming, and other common uses of hashes. It is not an // integer type (although it can be converted to one) because it is risky // to assume much about the internals of a hash_code. In particular, each // execution of the program has a high probability of producing a different // hash_code for a given input. Thus their values are not stable to save or // persist, and should only be used during the execution for the // construction of hashing datastructures. // // -- 'hash_value' is a function designed to be overloaded for each // user-defined type which wishes to be used within a hashing context. It // should be overloaded within the user-defined type's namespace and found // via ADL. Overloads for primitive types are provided by this library. // // -- 'hash_combine' and 'hash_combine_range' are functions designed to aid // programmers in easily and intuitively combining a set of data into // a single hash_code for their object. They should only logically be used // within the implementation of a 'hash_value' routine or similar context. // // Note that 'hash_combine_range' contains very special logic for hashing // a contiguous array of integers or pointers. This logic is *extremely* fast, // on a modern Intel "Gainestown" Xeon (Nehalem uarch) @2.2 GHz, these were // benchmarked at over 6.5 GiB/s for large keys, and <20 cycles/hash for keys // under 32-bytes. // //===----------------------------------------------------------------------===// #ifndef LLVM_ADT_HASHING_H #define LLVM_ADT_HASHING_H #include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/type_traits.h" #include #include #include #include #include #include namespace llvm { /// An opaque object representing a hash code. /// /// This object represents the result of hashing some entity. It is intended to /// be used to implement hashtables or other hashing-based data structures. /// While it wraps and exposes a numeric value, this value should not be /// trusted to be stable or predictable across processes or executions. /// /// In order to obtain the hash_code for an object 'x': /// \code /// using llvm::hash_value; /// llvm::hash_code code = hash_value(x); /// \endcode class hash_code { size_t value; public: /// Default construct a hash_code. /// Note that this leaves the value uninitialized. hash_code() = default; /// Form a hash code directly from a numerical value. hash_code(size_t value) : value(value) {} /// Convert the hash code to its numerical value for use. /*explicit*/ operator size_t() const { return value; } friend bool operator==(const hash_code &lhs, const hash_code &rhs) { return lhs.value == rhs.value; } friend bool operator!=(const hash_code &lhs, const hash_code &rhs) { return lhs.value != rhs.value; } /// Allow a hash_code to be directly run through hash_value. friend size_t hash_value(const hash_code &code) { return code.value; } }; /// Compute a hash_code for any integer value. /// /// Note that this function is intended to compute the same hash_code for /// a particular value without regard to the pre-promotion type. This is in /// contrast to hash_combine which may produce different hash_codes for /// differing argument types even if they would implicit promote to a common /// type without changing the value. template std::enable_if_t::value, hash_code> hash_value(T value); /// Compute a hash_code for a pointer's address. /// /// N.B.: This hashes the *address*. Not the value and not the type. template hash_code hash_value(const T *ptr); /// Compute a hash_code for a pair of objects. template hash_code hash_value(const std::pair &arg); /// Compute a hash_code for a tuple. template hash_code hash_value(const std::tuple &arg); /// Compute a hash_code for a standard string. template hash_code hash_value(const std::basic_string &arg); /// Override the execution seed with a fixed value. /// /// This hashing library uses a per-execution seed designed to change on each /// run with high probability in order to ensure that the hash codes are not /// attackable and to ensure that output which is intended to be stable does /// not rely on the particulars of the hash codes produced. /// /// That said, there are use cases where it is important to be able to /// reproduce *exactly* a specific behavior. To that end, we provide a function /// which will forcibly set the seed to a fixed value. This must be done at the /// start of the program, before any hashes are computed. Also, it cannot be /// undone. This makes it thread-hostile and very hard to use outside of /// immediately on start of a simple program designed for reproducible /// behavior. void set_fixed_execution_hash_seed(uint64_t fixed_value); // All of the implementation details of actually computing the various hash // code values are held within this namespace. These routines are included in // the header file mainly to allow inlining and constant propagation. namespace hashing { namespace detail { inline uint64_t fetch64(const char *p) { uint64_t result; memcpy(&result, p, sizeof(result)); if (sys::IsBigEndianHost) sys::swapByteOrder(result); return result; } inline uint32_t fetch32(const char *p) { uint32_t result; memcpy(&result, p, sizeof(result)); if (sys::IsBigEndianHost) sys::swapByteOrder(result); return result; } /// Some primes between 2^63 and 2^64 for various uses. static constexpr uint64_t k0 = 0xc3a5c85c97cb3127ULL; static constexpr uint64_t k1 = 0xb492b66fbe98f273ULL; static constexpr uint64_t k2 = 0x9ae16a3b2f90404fULL; static constexpr uint64_t k3 = 0xc949d7c7509e6557ULL; /// Bitwise right rotate. /// Normally this will compile to a single instruction, especially if the /// shift is a manifest constant. inline uint64_t rotate(uint64_t val, size_t shift) { // Avoid shifting by 64: doing so yields an undefined result. return shift == 0 ? val : ((val >> shift) | (val << (64 - shift))); } inline uint64_t shift_mix(uint64_t val) { return val ^ (val >> 47); } inline uint64_t hash_16_bytes(uint64_t low, uint64_t high) { // Murmur-inspired hashing. const uint64_t kMul = 0x9ddfea08eb382d69ULL; uint64_t a = (low ^ high) * kMul; a ^= (a >> 47); uint64_t b = (high ^ a) * kMul; b ^= (b >> 47); b *= kMul; return b; } inline uint64_t hash_1to3_bytes(const char *s, size_t len, uint64_t seed) { uint8_t a = s[0]; uint8_t b = s[len >> 1]; uint8_t c = s[len - 1]; uint32_t y = static_cast(a) + (static_cast(b) << 8); uint32_t z = static_cast(len) + (static_cast(c) << 2); return shift_mix(y * k2 ^ z * k3 ^ seed) * k2; } inline uint64_t hash_4to8_bytes(const char *s, size_t len, uint64_t seed) { uint64_t a = fetch32(s); return hash_16_bytes(len + (a << 3), seed ^ fetch32(s + len - 4)); } inline uint64_t hash_9to16_bytes(const char *s, size_t len, uint64_t seed) { uint64_t a = fetch64(s); uint64_t b = fetch64(s + len - 8); return hash_16_bytes(seed ^ a, rotate(b + len, len)) ^ b; } inline uint64_t hash_17to32_bytes(const char *s, size_t len, uint64_t seed) { uint64_t a = fetch64(s) * k1; uint64_t b = fetch64(s + 8); uint64_t c = fetch64(s + len - 8) * k2; uint64_t d = fetch64(s + len - 16) * k0; return hash_16_bytes(rotate(a - b, 43) + rotate(c ^ seed, 30) + d, a + rotate(b ^ k3, 20) - c + len + seed); } inline uint64_t hash_33to64_bytes(const char *s, size_t len, uint64_t seed) { uint64_t z = fetch64(s + 24); uint64_t a = fetch64(s) + (len + fetch64(s + len - 16)) * k0; uint64_t b = rotate(a + z, 52); uint64_t c = rotate(a, 37); a += fetch64(s + 8); c += rotate(a, 7); a += fetch64(s + 16); uint64_t vf = a + z; uint64_t vs = b + rotate(a, 31) + c; a = fetch64(s + 16) + fetch64(s + len - 32); z = fetch64(s + len - 8); b = rotate(a + z, 52); c = rotate(a, 37); a += fetch64(s + len - 24); c += rotate(a, 7); a += fetch64(s + len - 16); uint64_t wf = a + z; uint64_t ws = b + rotate(a, 31) + c; uint64_t r = shift_mix((vf + ws) * k2 + (wf + vs) * k0); return shift_mix((seed ^ (r * k0)) + vs) * k2; } inline uint64_t hash_short(const char *s, size_t length, uint64_t seed) { if (length >= 4 && length <= 8) return hash_4to8_bytes(s, length, seed); if (length > 8 && length <= 16) return hash_9to16_bytes(s, length, seed); if (length > 16 && length <= 32) return hash_17to32_bytes(s, length, seed); if (length > 32) return hash_33to64_bytes(s, length, seed); if (length != 0) return hash_1to3_bytes(s, length, seed); return k2 ^ seed; } /// The intermediate state used during hashing. /// Currently, the algorithm for computing hash codes is based on CityHash and /// keeps 56 bytes of arbitrary state. struct hash_state { uint64_t h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0; /// Create a new hash_state structure and initialize it based on the /// seed and the first 64-byte chunk. /// This effectively performs the initial mix. static hash_state create(const char *s, uint64_t seed) { hash_state state = { 0, seed, hash_16_bytes(seed, k1), rotate(seed ^ k1, 49), seed * k1, shift_mix(seed), 0 }; state.h6 = hash_16_bytes(state.h4, state.h5); state.mix(s); return state; } /// Mix 32-bytes from the input sequence into the 16-bytes of 'a' /// and 'b', including whatever is already in 'a' and 'b'. static void mix_32_bytes(const char *s, uint64_t &a, uint64_t &b) { a += fetch64(s); uint64_t c = fetch64(s + 24); b = rotate(b + a + c, 21); uint64_t d = a; a += fetch64(s + 8) + fetch64(s + 16); b += rotate(a, 44) + d; a += c; } /// Mix in a 64-byte buffer of data. /// We mix all 64 bytes even when the chunk length is smaller, but we /// record the actual length. void mix(const char *s) { h0 = rotate(h0 + h1 + h3 + fetch64(s + 8), 37) * k1; h1 = rotate(h1 + h4 + fetch64(s + 48), 42) * k1; h0 ^= h6; h1 += h3 + fetch64(s + 40); h2 = rotate(h2 + h5, 33) * k1; h3 = h4 * k1; h4 = h0 + h5; mix_32_bytes(s, h3, h4); h5 = h2 + h6; h6 = h1 + fetch64(s + 16); mix_32_bytes(s + 32, h5, h6); std::swap(h2, h0); } /// Compute the final 64-bit hash code value based on the current /// state and the length of bytes hashed. uint64_t finalize(size_t length) { return hash_16_bytes(hash_16_bytes(h3, h5) + shift_mix(h1) * k1 + h2, hash_16_bytes(h4, h6) + shift_mix(length) * k1 + h0); } }; /// A global, fixed seed-override variable. /// /// This variable can be set using the \see llvm::set_fixed_execution_seed /// function. See that function for details. Do not, under any circumstances, /// set or read this variable. extern uint64_t fixed_seed_override; inline uint64_t get_execution_seed() { // FIXME: This needs to be a per-execution seed. This is just a placeholder // implementation. Switching to a per-execution seed is likely to flush out // instability bugs and so will happen as its own commit. // // However, if there is a fixed seed override set the first time this is // called, return that instead of the per-execution seed. const uint64_t seed_prime = 0xff51afd7ed558ccdULL; static uint64_t seed = fixed_seed_override ? fixed_seed_override : seed_prime; return seed; } /// Trait to indicate whether a type's bits can be hashed directly. /// /// A type trait which is true if we want to combine values for hashing by /// reading the underlying data. It is false if values of this type must /// first be passed to hash_value, and the resulting hash_codes combined. // // FIXME: We want to replace is_integral_or_enum and is_pointer here with // a predicate which asserts that comparing the underlying storage of two // values of the type for equality is equivalent to comparing the two values // for equality. For all the platforms we care about, this holds for integers // and pointers, but there are platforms where it doesn't and we would like to // support user-defined types which happen to satisfy this property. template struct is_hashable_data : std::integral_constant::value || std::is_pointer::value) && 64 % sizeof(T) == 0)> {}; // Special case std::pair to detect when both types are viable and when there // is no alignment-derived padding in the pair. This is a bit of a lie because // std::pair isn't truly POD, but it's close enough in all reasonable // implementations for our use case of hashing the underlying data. template struct is_hashable_data > : std::integral_constant::value && is_hashable_data::value && (sizeof(T) + sizeof(U)) == sizeof(std::pair))> {}; /// Helper to get the hashable data representation for a type. /// This variant is enabled when the type itself can be used. template std::enable_if_t::value, T> get_hashable_data(const T &value) { return value; } /// Helper to get the hashable data representation for a type. /// This variant is enabled when we must first call hash_value and use the /// result as our data. template std::enable_if_t::value, size_t> get_hashable_data(const T &value) { using ::llvm::hash_value; return hash_value(value); } /// Helper to store data from a value into a buffer and advance the /// pointer into that buffer. /// /// This routine first checks whether there is enough space in the provided /// buffer, and if not immediately returns false. If there is space, it /// copies the underlying bytes of value into the buffer, advances the /// buffer_ptr past the copied bytes, and returns true. template bool store_and_advance(char *&buffer_ptr, char *buffer_end, const T& value, size_t offset = 0) { size_t store_size = sizeof(value) - offset; if (buffer_ptr + store_size > buffer_end) return false; const char *value_data = reinterpret_cast(&value); memcpy(buffer_ptr, value_data + offset, store_size); buffer_ptr += store_size; return true; } /// Implement the combining of integral values into a hash_code. /// /// This overload is selected when the value type of the iterator is /// integral. Rather than computing a hash_code for each object and then /// combining them, this (as an optimization) directly combines the integers. template hash_code hash_combine_range_impl(InputIteratorT first, InputIteratorT last) { const uint64_t seed = get_execution_seed(); char buffer[64], *buffer_ptr = buffer; char *const buffer_end = std::end(buffer); while (first != last && store_and_advance(buffer_ptr, buffer_end, get_hashable_data(*first))) ++first; if (first == last) return hash_short(buffer, buffer_ptr - buffer, seed); assert(buffer_ptr == buffer_end); hash_state state = state.create(buffer, seed); size_t length = 64; while (first != last) { // Fill up the buffer. We don't clear it, which re-mixes the last round // when only a partial 64-byte chunk is left. buffer_ptr = buffer; while (first != last && store_and_advance(buffer_ptr, buffer_end, get_hashable_data(*first))) ++first; // Rotate the buffer if we did a partial fill in order to simulate doing // a mix of the last 64-bytes. That is how the algorithm works when we // have a contiguous byte sequence, and we want to emulate that here. std::rotate(buffer, buffer_ptr, buffer_end); // Mix this chunk into the current state. state.mix(buffer); length += buffer_ptr - buffer; }; return state.finalize(length); } /// Implement the combining of integral values into a hash_code. /// /// This overload is selected when the value type of the iterator is integral /// and when the input iterator is actually a pointer. Rather than computing /// a hash_code for each object and then combining them, this (as an /// optimization) directly combines the integers. Also, because the integers /// are stored in contiguous memory, this routine avoids copying each value /// and directly reads from the underlying memory. template std::enable_if_t::value, hash_code> hash_combine_range_impl(ValueT *first, ValueT *last) { const uint64_t seed = get_execution_seed(); const char *s_begin = reinterpret_cast(first); const char *s_end = reinterpret_cast(last); const size_t length = std::distance(s_begin, s_end); if (length <= 64) return hash_short(s_begin, length, seed); const char *s_aligned_end = s_begin + (length & ~63); hash_state state = state.create(s_begin, seed); s_begin += 64; while (s_begin != s_aligned_end) { state.mix(s_begin); s_begin += 64; } if (length & 63) state.mix(s_end - 64); return state.finalize(length); } } // namespace detail } // namespace hashing /// Compute a hash_code for a sequence of values. /// /// This hashes a sequence of values. It produces the same hash_code as /// 'hash_combine(a, b, c, ...)', but can run over arbitrary sized sequences /// and is significantly faster given pointers and types which can be hashed as /// a sequence of bytes. template hash_code hash_combine_range(InputIteratorT first, InputIteratorT last) { return ::llvm::hashing::detail::hash_combine_range_impl(first, last); } // Implementation details for hash_combine. namespace hashing { namespace detail { /// Helper class to manage the recursive combining of hash_combine /// arguments. /// /// This class exists to manage the state and various calls involved in the /// recursive combining of arguments used in hash_combine. It is particularly /// useful at minimizing the code in the recursive calls to ease the pain /// caused by a lack of variadic functions. struct hash_combine_recursive_helper { char buffer[64] = {}; hash_state state; const uint64_t seed; public: /// Construct a recursive hash combining helper. /// /// This sets up the state for a recursive hash combine, including getting /// the seed and buffer setup. hash_combine_recursive_helper() : seed(get_execution_seed()) {} /// Combine one chunk of data into the current in-flight hash. /// /// This merges one chunk of data into the hash. First it tries to buffer /// the data. If the buffer is full, it hashes the buffer into its /// hash_state, empties it, and then merges the new chunk in. This also /// handles cases where the data straddles the end of the buffer. template char *combine_data(size_t &length, char *buffer_ptr, char *buffer_end, T data) { if (!store_and_advance(buffer_ptr, buffer_end, data)) { // Check for skew which prevents the buffer from being packed, and do // a partial store into the buffer to fill it. This is only a concern // with the variadic combine because that formation can have varying // argument types. size_t partial_store_size = buffer_end - buffer_ptr; memcpy(buffer_ptr, &data, partial_store_size); // If the store fails, our buffer is full and ready to hash. We have to // either initialize the hash state (on the first full buffer) or mix // this buffer into the existing hash state. Length tracks the *hashed* // length, not the buffered length. if (length == 0) { state = state.create(buffer, seed); length = 64; } else { // Mix this chunk into the current state and bump length up by 64. state.mix(buffer); length += 64; } // Reset the buffer_ptr to the head of the buffer for the next chunk of // data. buffer_ptr = buffer; // Try again to store into the buffer -- this cannot fail as we only // store types smaller than the buffer. if (!store_and_advance(buffer_ptr, buffer_end, data, partial_store_size)) llvm_unreachable("buffer smaller than stored type"); } return buffer_ptr; } /// Recursive, variadic combining method. /// /// This function recurses through each argument, combining that argument /// into a single hash. template hash_code combine(size_t length, char *buffer_ptr, char *buffer_end, const T &arg, const Ts &...args) { buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg)); // Recurse to the next argument. return combine(length, buffer_ptr, buffer_end, args...); } /// Base case for recursive, variadic combining. /// /// The base case when combining arguments recursively is reached when all /// arguments have been handled. It flushes the remaining buffer and /// constructs a hash_code. hash_code combine(size_t length, char *buffer_ptr, char *buffer_end) { // Check whether the entire set of values fit in the buffer. If so, we'll // use the optimized short hashing routine and skip state entirely. if (length == 0) return hash_short(buffer, buffer_ptr - buffer, seed); // Mix the final buffer, rotating it if we did a partial fill in order to // simulate doing a mix of the last 64-bytes. That is how the algorithm // works when we have a contiguous byte sequence, and we want to emulate // that here. std::rotate(buffer, buffer_ptr, buffer_end); // Mix this chunk into the current state. state.mix(buffer); length += buffer_ptr - buffer; return state.finalize(length); } }; } // namespace detail } // namespace hashing /// Combine values into a single hash_code. /// /// This routine accepts a varying number of arguments of any type. It will /// attempt to combine them into a single hash_code. For user-defined types it /// attempts to call a \see hash_value overload (via ADL) for the type. For /// integer and pointer types it directly combines their data into the /// resulting hash_code. /// /// The result is suitable for returning from a user's hash_value /// *implementation* for their user-defined type. Consumers of a type should /// *not* call this routine, they should instead call 'hash_value'. template hash_code hash_combine(const Ts &...args) { // Recursively hash each argument using a helper class. ::llvm::hashing::detail::hash_combine_recursive_helper helper; return helper.combine(0, helper.buffer, helper.buffer + 64, args...); } // Implementation details for implementations of hash_value overloads provided // here. namespace hashing { namespace detail { /// Helper to hash the value of a single integer. /// /// Overloads for smaller integer types are not provided to ensure consistent /// behavior in the presence of integral promotions. Essentially, /// "hash_value('4')" and "hash_value('0' + 4)" should be the same. inline hash_code hash_integer_value(uint64_t value) { // Similar to hash_4to8_bytes but using a seed instead of length. const uint64_t seed = get_execution_seed(); const char *s = reinterpret_cast(&value); const uint64_t a = fetch32(s); return hash_16_bytes(seed + (a << 3), fetch32(s + 4)); } } // namespace detail } // namespace hashing // Declared and documented above, but defined here so that any of the hashing // infrastructure is available. template std::enable_if_t::value, hash_code> hash_value(T value) { return ::llvm::hashing::detail::hash_integer_value( static_cast(value)); } // Declared and documented above, but defined here so that any of the hashing // infrastructure is available. template hash_code hash_value(const T *ptr) { return ::llvm::hashing::detail::hash_integer_value( reinterpret_cast(ptr)); } // Declared and documented above, but defined here so that any of the hashing // infrastructure is available. template hash_code hash_value(const std::pair &arg) { return hash_combine(arg.first, arg.second); } // Implementation details for the hash_value overload for std::tuple<...>(...). namespace hashing { namespace detail { template hash_code hash_value_tuple_helper(const std::tuple &arg, std::index_sequence) { return hash_combine(std::get(arg)...); } } // namespace detail } // namespace hashing template hash_code hash_value(const std::tuple &arg) { // TODO: Use std::apply when LLVM starts using C++17. return ::llvm::hashing::detail::hash_value_tuple_helper( arg, typename std::index_sequence_for()); } // Declared and documented above, but defined here so that any of the hashing // infrastructure is available. template hash_code hash_value(const std::basic_string &arg) { return hash_combine_range(arg.begin(), arg.end()); } } // namespace llvm #endif symbolic-demangle-12.4.0/vendor/swift/include/llvm/ADT/None.h000064400000000000000000000017271046102023000220200ustar 00000000000000//===-- None.h - Simple null value for implicit construction ------*- C++ -*-=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file provides None, an enumerator for use in implicit constructors // of various (usually templated) types to make such construction more // terse. // //===----------------------------------------------------------------------===// #ifndef LLVM_ADT_NONE_H #define LLVM_ADT_NONE_H namespace llvm { /// A simple null object to allow implicit construction of Optional /// and similar types without having to spell out the specialization's name. // (constant value 1 in an attempt to workaround MSVC build issue... ) enum class NoneType { None = 1 }; const NoneType None = NoneType::None; } #endif symbolic-demangle-12.4.0/vendor/swift/include/llvm/ADT/Optional.h000064400000000000000000000317031046102023000227030ustar 00000000000000//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file provides Optional, a template class modeled in the spirit of // OCaml's 'opt' variant. The idea is to strongly type whether or not // a value can be optional. // //===----------------------------------------------------------------------===// #ifndef LLVM_ADT_OPTIONAL_H #define LLVM_ADT_OPTIONAL_H #include "llvm/ADT/Hashing.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLForwardCompat.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/type_traits.h" #include #include #include #include namespace llvm { class raw_ostream; namespace optional_detail { /// Storage for any type. // // The specialization condition intentionally uses // llvm::is_trivially_copy_constructible instead of // std::is_trivially_copy_constructible. GCC versions prior to 7.4 may // instantiate the copy constructor of `T` when // std::is_trivially_copy_constructible is instantiated. This causes // compilation to fail if we query the trivially copy constructible property of // a class which is not copy constructible. // // The current implementation of OptionalStorage insists that in order to use // the trivial specialization, the value_type must be trivially copy // constructible and trivially copy assignable due to =default implementations // of the copy/move constructor/assignment. It does not follow that this is // necessarily the case std::is_trivially_copyable is true (hence the expanded // specialization condition). // // The move constructible / assignable conditions emulate the remaining behavior // of std::is_trivially_copyable. template ::value && std::is_trivially_copy_assignable::value && (std::is_trivially_move_constructible::value || !std::is_move_constructible::value) && (std::is_trivially_move_assignable::value || !std::is_move_assignable::value))> class OptionalStorage { union { char empty; T value; }; bool hasVal; public: ~OptionalStorage() { reset(); } constexpr OptionalStorage() noexcept : empty(), hasVal(false) {} constexpr OptionalStorage(OptionalStorage const &other) : OptionalStorage() { if (other.hasValue()) { emplace(other.value); } } constexpr OptionalStorage(OptionalStorage &&other) : OptionalStorage() { if (other.hasValue()) { emplace(std::move(other.value)); } } template constexpr explicit OptionalStorage(in_place_t, Args &&... args) : value(std::forward(args)...), hasVal(true) {} void reset() noexcept { if (hasVal) { value.~T(); hasVal = false; } } constexpr bool hasValue() const noexcept { return hasVal; } T &getValue() LLVM_LVALUE_FUNCTION noexcept { assert(hasVal); return value; } constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { assert(hasVal); return value; } #if LLVM_HAS_RVALUE_REFERENCE_THIS T &&getValue() && noexcept { assert(hasVal); return std::move(value); } #endif template void emplace(Args &&... args) { reset(); ::new ((void *)std::addressof(value)) T(std::forward(args)...); hasVal = true; } OptionalStorage &operator=(T const &y) { if (hasValue()) { value = y; } else { ::new ((void *)std::addressof(value)) T(y); hasVal = true; } return *this; } OptionalStorage &operator=(T &&y) { if (hasValue()) { value = std::move(y); } else { ::new ((void *)std::addressof(value)) T(std::move(y)); hasVal = true; } return *this; } OptionalStorage &operator=(OptionalStorage const &other) { if (other.hasValue()) { if (hasValue()) { value = other.value; } else { ::new ((void *)std::addressof(value)) T(other.value); hasVal = true; } } else { reset(); } return *this; } OptionalStorage &operator=(OptionalStorage &&other) { if (other.hasValue()) { if (hasValue()) { value = std::move(other.value); } else { ::new ((void *)std::addressof(value)) T(std::move(other.value)); hasVal = true; } } else { reset(); } return *this; } }; template class OptionalStorage { union { char empty; T value; }; bool hasVal = false; public: ~OptionalStorage() = default; constexpr OptionalStorage() noexcept : empty{} {} constexpr OptionalStorage(OptionalStorage const &other) = default; constexpr OptionalStorage(OptionalStorage &&other) = default; OptionalStorage &operator=(OptionalStorage const &other) = default; OptionalStorage &operator=(OptionalStorage &&other) = default; template constexpr explicit OptionalStorage(in_place_t, Args &&... args) : value(std::forward(args)...), hasVal(true) {} void reset() noexcept { if (hasVal) { value.~T(); hasVal = false; } } constexpr bool hasValue() const noexcept { return hasVal; } T &getValue() LLVM_LVALUE_FUNCTION noexcept { assert(hasVal); return value; } constexpr T const &getValue() const LLVM_LVALUE_FUNCTION noexcept { assert(hasVal); return value; } #if LLVM_HAS_RVALUE_REFERENCE_THIS T &&getValue() && noexcept { assert(hasVal); return std::move(value); } #endif template void emplace(Args &&... args) { reset(); ::new ((void *)std::addressof(value)) T(std::forward(args)...); hasVal = true; } OptionalStorage &operator=(T const &y) { if (hasValue()) { value = y; } else { ::new ((void *)std::addressof(value)) T(y); hasVal = true; } return *this; } OptionalStorage &operator=(T &&y) { if (hasValue()) { value = std::move(y); } else { ::new ((void *)std::addressof(value)) T(std::move(y)); hasVal = true; } return *this; } }; } // namespace optional_detail template class Optional { optional_detail::OptionalStorage Storage; public: using value_type = T; constexpr Optional() {} constexpr Optional(NoneType) {} constexpr Optional(const T &y) : Storage(in_place, y) {} constexpr Optional(const Optional &O) = default; constexpr Optional(T &&y) : Storage(in_place, std::move(y)) {} constexpr Optional(Optional &&O) = default; template constexpr Optional(in_place_t, ArgTypes &&...Args) : Storage(in_place, std::forward(Args)...) {} Optional &operator=(T &&y) { Storage = std::move(y); return *this; } Optional &operator=(Optional &&O) = default; /// Create a new object by constructing it in place with the given arguments. template void emplace(ArgTypes &&... Args) { Storage.emplace(std::forward(Args)...); } static constexpr Optional create(const T *y) { return y ? Optional(*y) : Optional(); } Optional &operator=(const T &y) { Storage = y; return *this; } Optional &operator=(const Optional &O) = default; void reset() { Storage.reset(); } constexpr const T *getPointer() const { return &Storage.getValue(); } T *getPointer() { return &Storage.getValue(); } constexpr const T &getValue() const LLVM_LVALUE_FUNCTION { return Storage.getValue(); } T &getValue() LLVM_LVALUE_FUNCTION { return Storage.getValue(); } constexpr explicit operator bool() const { return hasValue(); } constexpr bool hasValue() const { return Storage.hasValue(); } constexpr const T *operator->() const { return getPointer(); } T *operator->() { return getPointer(); } constexpr const T &operator*() const LLVM_LVALUE_FUNCTION { return getValue(); } T &operator*() LLVM_LVALUE_FUNCTION { return getValue(); } template constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION { return hasValue() ? getValue() : std::forward(value); } /// Apply a function to the value if present; otherwise return None. template auto map(const Function &F) const LLVM_LVALUE_FUNCTION -> Optional { if (*this) return F(getValue()); return None; } #if LLVM_HAS_RVALUE_REFERENCE_THIS T &&getValue() && { return std::move(Storage.getValue()); } T &&operator*() && { return std::move(Storage.getValue()); } template T getValueOr(U &&value) && { return hasValue() ? std::move(getValue()) : std::forward(value); } /// Apply a function to the value if present; otherwise return None. template auto map(const Function &F) && -> Optional { if (*this) return F(std::move(*this).getValue()); return None; } #endif }; template llvm::hash_code hash_value(const Optional &O) { return O ? hash_combine(true, *O) : hash_value(false); } template constexpr bool operator==(const Optional &X, const Optional &Y) { if (X && Y) return *X == *Y; return X.hasValue() == Y.hasValue(); } template constexpr bool operator!=(const Optional &X, const Optional &Y) { return !(X == Y); } template constexpr bool operator<(const Optional &X, const Optional &Y) { if (X && Y) return *X < *Y; return X.hasValue() < Y.hasValue(); } template constexpr bool operator<=(const Optional &X, const Optional &Y) { return !(Y < X); } template constexpr bool operator>(const Optional &X, const Optional &Y) { return Y < X; } template constexpr bool operator>=(const Optional &X, const Optional &Y) { return !(X < Y); } template constexpr bool operator==(const Optional &X, NoneType) { return !X; } template constexpr bool operator==(NoneType, const Optional &X) { return X == None; } template constexpr bool operator!=(const Optional &X, NoneType) { return !(X == None); } template constexpr bool operator!=(NoneType, const Optional &X) { return X != None; } template constexpr bool operator<(const Optional &, NoneType) { return false; } template constexpr bool operator<(NoneType, const Optional &X) { return X.hasValue(); } template constexpr bool operator<=(const Optional &X, NoneType) { return !(None < X); } template constexpr bool operator<=(NoneType, const Optional &X) { return !(X < None); } template constexpr bool operator>(const Optional &X, NoneType) { return None < X; } template constexpr bool operator>(NoneType, const Optional &X) { return X < None; } template constexpr bool operator>=(const Optional &X, NoneType) { return None <= X; } template constexpr bool operator>=(NoneType, const Optional &X) { return X <= None; } template constexpr bool operator==(const Optional &X, const T &Y) { return X && *X == Y; } template constexpr bool operator==(const T &X, const Optional &Y) { return Y && X == *Y; } template constexpr bool operator!=(const Optional &X, const T &Y) { return !(X == Y); } template constexpr bool operator!=(const T &X, const Optional &Y) { return !(X == Y); } template constexpr bool operator<(const Optional &X, const T &Y) { return !X || *X < Y; } template constexpr bool operator<(const T &X, const Optional &Y) { return Y && X < *Y; } template constexpr bool operator<=(const Optional &X, const T &Y) { return !(Y < X); } template constexpr bool operator<=(const T &X, const Optional &Y) { return !(Y < X); } template constexpr bool operator>(const Optional &X, const T &Y) { return Y < X; } template constexpr bool operator>(const T &X, const Optional &Y) { return Y < X; } template constexpr bool operator>=(const Optional &X, const T &Y) { return !(X < Y); } template constexpr bool operator>=(const T &X, const Optional &Y) { return !(X < Y); } raw_ostream &operator<<(raw_ostream &OS, NoneType); template () << std::declval())> raw_ostream &operator<<(raw_ostream &OS, const Optional &O) { if (O) OS << *O; else OS << None; return OS; } } // end namespace llvm #endif // LLVM_ADT_OPTIONAL_H symbolic-demangle-12.4.0/vendor/swift/include/llvm/ADT/STLExtras.h000064400000000000000000002231111046102023000227430ustar 00000000000000//===- llvm/ADT/STLExtras.h - Useful STL related functions ------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains some templates that are useful if you are working with the // STL at all. // // No library is required when using these functions. // //===----------------------------------------------------------------------===// #ifndef LLVM_ADT_STLEXTRAS_H #define LLVM_ADT_STLEXTRAS_H #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Config/abi-breaking.h" #include "llvm/Support/ErrorHandling.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef EXPENSIVE_CHECKS #include // for std::mt19937 #endif namespace llvm { // Only used by compiler if both template types are the same. Useful when // using SFINAE to test for the existence of member functions. template struct SameType; namespace detail { template using IterOfRange = decltype(std::begin(std::declval())); template using ValueOfRange = typename std::remove_reference()))>::type; } // end namespace detail //===----------------------------------------------------------------------===// // Extra additions to //===----------------------------------------------------------------------===// template struct make_const_ptr { using type = typename std::add_pointer::type>::type; }; template struct make_const_ref { using type = typename std::add_lvalue_reference< typename std::add_const::type>::type; }; namespace detail { template using void_t = void; template class Op, class... Args> struct detector { using value_t = std::false_type; }; template