//===--- RustDemangle.cpp ---------------------------------------*- 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 defines a demangler for Rust v0 mangled symbols as specified in // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html // //===----------------------------------------------------------------------===// #include "llvm/Demangle/Demangle.h" #include "llvm/Demangle/StringViewExtras.h" #include "llvm/Demangle/Utility.h" #include <algorithm> #include <cassert> #include <cstdint> #include <cstring> #include <limits> #include <string_view> usingnamespacellvm; OutputBuffer; ScopedOverride; starts_with; namespace { struct Identifier { … }; enum class BasicType { … }; enum class IsInType { … }; enum class LeaveGenericsOpen { … }; class Demangler { … }; } // namespace char *llvm::rustDemangle(std::string_view MangledName) { … } Demangler::Demangler(size_t MaxRecursionLevel) : … { … } static inline bool isDigit(const char C) { … } static inline bool isHexDigit(const char C) { … } static inline bool isLower(const char C) { … } static inline bool isUpper(const char C) { … } /// Returns true if C is a valid mangled character: <0-9a-zA-Z_>. static inline bool isValid(const char C) { … } // Demangles Rust v0 mangled symbol. Returns true when successful, and false // otherwise. The demangled symbol is stored in Output field. It is // responsibility of the caller to free the memory behind the output stream. // // <symbol-name> = "_R" <path> [<instantiating-crate>] bool Demangler::demangle(std::string_view Mangled) { … } // Demangles a path. InType indicates whether a path is inside a type. When // LeaveOpen is true, a closing `>` after generic arguments is omitted from the // output. Return value indicates whether generics arguments have been left // open. // // <path> = "C" <identifier> // crate root // | "M" <impl-path> <type> // <T> (inherent impl) // | "X" <impl-path> <type> <path> // <T as Trait> (trait impl) // | "Y" <type> <path> // <T as Trait> (trait definition) // | "N" <ns> <path> <identifier> // ...::ident (nested path) // | "I" <path> {<generic-arg>} "E" // ...<T, U> (generic args) // | <backref> // <identifier> = [<disambiguator>] <undisambiguated-identifier> // <ns> = "C" // closure // | "S" // shim // | <A-Z> // other special namespaces // | <a-z> // internal namespaces bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) { … } // <impl-path> = [<disambiguator>] <path> // <disambiguator> = "s" <base-62-number> void Demangler::demangleImplPath(IsInType InType) { … } // <generic-arg> = <lifetime> // | <type> // | "K" <const> // <lifetime> = "L" <base-62-number> void Demangler::demangleGenericArg() { … } // <basic-type> = "a" // i8 // | "b" // bool // | "c" // char // | "d" // f64 // | "e" // str // | "f" // f32 // | "h" // u8 // | "i" // isize // | "j" // usize // | "l" // i32 // | "m" // u32 // | "n" // i128 // | "o" // u128 // | "s" // i16 // | "t" // u16 // | "u" // () // | "v" // ... // | "x" // i64 // | "y" // u64 // | "z" // ! // | "p" // placeholder (e.g. for generic params), shown as _ static bool parseBasicType(char C, BasicType &Type) { … } void Demangler::printBasicType(BasicType Type) { … } // <type> = | <basic-type> // | <path> // named type // | "A" <type> <const> // [T; N] // | "S" <type> // [T] // | "T" {<type>} "E" // (T1, T2, T3, ...) // | "R" [<lifetime>] <type> // &T // | "Q" [<lifetime>] <type> // &mut T // | "P" <type> // *const T // | "O" <type> // *mut T // | "F" <fn-sig> // fn(...) -> ... // | "D" <dyn-bounds> <lifetime> // dyn Trait<Assoc = X> + Send + 'a // | <backref> // backref void Demangler::demangleType() { … } // <fn-sig> := [<binder>] ["U"] ["K" <abi>] {<type>} "E" <type> // <abi> = "C" // | <undisambiguated-identifier> void Demangler::demangleFnSig() { … } // <dyn-bounds> = [<binder>] {<dyn-trait>} "E" void Demangler::demangleDynBounds() { … } // <dyn-trait> = <path> {<dyn-trait-assoc-binding>} // <dyn-trait-assoc-binding> = "p" <undisambiguated-identifier> <type> void Demangler::demangleDynTrait() { … } // Demangles optional binder and updates the number of bound lifetimes. // // <binder> = "G" <base-62-number> void Demangler::demangleOptionalBinder() { … } // <const> = <basic-type> <const-data> // | "p" // placeholder // | <backref> void Demangler::demangleConst() { … } // <const-data> = ["n"] <hex-number> void Demangler::demangleConstInt() { … } // <const-data> = "0_" // false // | "1_" // true void Demangler::demangleConstBool() { … } /// Returns true if CodePoint represents a printable ASCII character. static bool isAsciiPrintable(uint64_t CodePoint) { … } // <const-data> = <hex-number> void Demangler::demangleConstChar() { … } // <undisambiguated-identifier> = ["u"] <decimal-number> ["_"] <bytes> Identifier Demangler::parseIdentifier() { … } // Parses optional base 62 number. The presence of a number is determined using // Tag. Returns 0 when tag is absent and parsed value + 1 otherwise // // This function is intended for parsing disambiguators and binders which when // not present have their value interpreted as 0, and otherwise as decoded // value + 1. For example for binders, value for "G_" is 1, for "G0_" value is // 2. When "G" is absent value is 0. uint64_t Demangler::parseOptionalBase62Number(char Tag) { … } // Parses base 62 number with <0-9a-zA-Z> as digits. Number is terminated by // "_". All values are offset by 1, so that "_" encodes 0, "0_" encodes 1, // "1_" encodes 2, etc. // // <base-62-number> = {<0-9a-zA-Z>} "_" uint64_t Demangler::parseBase62Number() { … } // Parses a decimal number that had been encoded without any leading zeros. // // <decimal-number> = "0" // | <1-9> {<0-9>} uint64_t Demangler::parseDecimalNumber() { … } // Parses a hexadecimal number with <0-9a-f> as a digits. Returns the parsed // value and stores hex digits in HexDigits. The return value is unspecified if // HexDigits.size() > 16. // // <hex-number> = "0_" // | <1-9a-f> {<0-9a-f>} "_" uint64_t Demangler::parseHexNumber(std::string_view &HexDigits) { … } void Demangler::print(char C) { … } void Demangler::print(std::string_view S) { … } void Demangler::printDecimalNumber(uint64_t N) { … } // Prints a lifetime. An index 0 always represents an erased lifetime. Indices // starting from 1, are De Bruijn indices, referring to higher-ranked lifetimes // bound by one of the enclosing binders. void Demangler::printLifetime(uint64_t Index) { … } static inline bool decodePunycodeDigit(char C, size_t &Value) { … } static void removeNullBytes(OutputBuffer &Output, size_t StartIdx) { … } // Encodes code point as UTF-8 and stores results in Output. Returns false if // CodePoint is not a valid unicode scalar value. static inline bool encodeUTF8(size_t CodePoint, char *Output) { … } // Decodes string encoded using punycode and appends results to Output. // Returns true if decoding was successful. static bool decodePunycode(std::string_view Input, OutputBuffer &Output) { … } void Demangler::printIdentifier(Identifier Ident) { … } char Demangler::look() const { … } char Demangler::consume() { … } bool Demangler::consumeIf(char Prefix) { … } /// Computes A + B. When computation wraps around sets the error and returns /// false. Otherwise assigns the result to A and returns true. bool Demangler::addAssign(uint64_t &A, uint64_t B) { … } /// Computes A * B. When computation wraps around sets the error and returns /// false. Otherwise assigns the result to A and returns true. bool Demangler::mulAssign(uint64_t &A, uint64_t B) { … }