#include "llvm/Demangle/Demangle.h"
#include "llvm/Demangle/StringView.h"
#include "llvm/Demangle/Utility.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <limits>
using namespace llvm;
using llvm::itanium_demangle::OutputBuffer;
using llvm::itanium_demangle::ScopedOverride;
using llvm::itanium_demangle::StringView;
namespace {
struct Identifier {
StringView Name;
bool Punycode;
bool empty() const { return Name.empty(); }
};
enum class BasicType {
Bool,
Char,
I8,
I16,
I32,
I64,
I128,
ISize,
U8,
U16,
U32,
U64,
U128,
USize,
F32,
F64,
Str,
Placeholder,
Unit,
Variadic,
Never,
};
enum class IsInType {
No,
Yes,
};
enum class LeaveGenericsOpen {
No,
Yes,
};
class Demangler {
size_t MaxRecursionLevel;
size_t RecursionLevel;
size_t BoundLifetimes;
StringView Input;
size_t Position;
bool Print;
bool Error;
public:
OutputBuffer Output;
Demangler(size_t MaxRecursionLevel = 500);
bool demangle(StringView MangledName);
private:
bool demanglePath(IsInType Type,
LeaveGenericsOpen LeaveOpen = LeaveGenericsOpen::No);
void demangleImplPath(IsInType InType);
void demangleGenericArg();
void demangleType();
void demangleFnSig();
void demangleDynBounds();
void demangleDynTrait();
void demangleOptionalBinder();
void demangleConst();
void demangleConstInt();
void demangleConstBool();
void demangleConstChar();
template <typename Callable> void demangleBackref(Callable Demangler) {
uint64_t Backref = parseBase62Number();
if (Error || Backref >= Position) {
Error = true;
return;
}
if (!Print)
return;
ScopedOverride<size_t> SavePosition(Position, Position);
Position = Backref;
Demangler();
}
Identifier parseIdentifier();
uint64_t parseOptionalBase62Number(char Tag);
uint64_t parseBase62Number();
uint64_t parseDecimalNumber();
uint64_t parseHexNumber(StringView &HexDigits);
void print(char C);
void print(StringView S);
void printDecimalNumber(uint64_t N);
void printBasicType(BasicType);
void printLifetime(uint64_t Index);
void printIdentifier(Identifier Ident);
char look() const;
char consume();
bool consumeIf(char Prefix);
bool addAssign(uint64_t &A, uint64_t B);
bool mulAssign(uint64_t &A, uint64_t B);
};
}
char *llvm::rustDemangle(const char *MangledName) {
if (MangledName == nullptr)
return nullptr;
StringView Mangled(MangledName);
if (!Mangled.startsWith("_R"))
return nullptr;
Demangler D;
if (!initializeOutputBuffer(nullptr, nullptr, D.Output, 1024))
return nullptr;
if (!D.demangle(Mangled)) {
std::free(D.Output.getBuffer());
return nullptr;
}
D.Output += '\0';
return D.Output.getBuffer();
}
Demangler::Demangler(size_t MaxRecursionLevel)
: MaxRecursionLevel(MaxRecursionLevel) {}
static inline bool isDigit(const char C) { return '0' <= C && C <= '9'; }
static inline bool isHexDigit(const char C) {
return ('0' <= C && C <= '9') || ('a' <= C && C <= 'f');
}
static inline bool isLower(const char C) { return 'a' <= C && C <= 'z'; }
static inline bool isUpper(const char C) { return 'A' <= C && C <= 'Z'; }
static inline bool isValid(const char C) {
return isDigit(C) || isLower(C) || isUpper(C) || C == '_';
}
bool Demangler::demangle(StringView Mangled) {
Position = 0;
Error = false;
Print = true;
RecursionLevel = 0;
BoundLifetimes = 0;
if (!Mangled.consumeFront("_R")) {
Error = true;
return false;
}
size_t Dot = Mangled.find('.');
Input = Mangled.substr(0, Dot);
StringView Suffix = Mangled.dropFront(Dot);
demanglePath(IsInType::No);
if (Position != Input.size()) {
ScopedOverride<bool> SavePrint(Print, false);
demanglePath(IsInType::No);
}
if (Position != Input.size())
Error = true;
if (!Suffix.empty()) {
print(" (");
print(Suffix);
print(")");
}
return !Error;
}
bool Demangler::demanglePath(IsInType InType, LeaveGenericsOpen LeaveOpen) {
if (Error || RecursionLevel >= MaxRecursionLevel) {
Error = true;
return false;
}
ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
switch (consume()) {
case 'C': {
parseOptionalBase62Number('s');
printIdentifier(parseIdentifier());
break;
}
case 'M': {
demangleImplPath(InType);
print("<");
demangleType();
print(">");
break;
}
case 'X': {
demangleImplPath(InType);
print("<");
demangleType();
print(" as ");
demanglePath(IsInType::Yes);
print(">");
break;
}
case 'Y': {
print("<");
demangleType();
print(" as ");
demanglePath(IsInType::Yes);
print(">");
break;
}
case 'N': {
char NS = consume();
if (!isLower(NS) && !isUpper(NS)) {
Error = true;
break;
}
demanglePath(InType);
uint64_t Disambiguator = parseOptionalBase62Number('s');
Identifier Ident = parseIdentifier();
if (isUpper(NS)) {
print("::{");
if (NS == 'C')
print("closure");
else if (NS == 'S')
print("shim");
else
print(NS);
if (!Ident.empty()) {
print(":");
printIdentifier(Ident);
}
print('#');
printDecimalNumber(Disambiguator);
print('}');
} else {
if (!Ident.empty()) {
print("::");
printIdentifier(Ident);
}
}
break;
}
case 'I': {
demanglePath(InType);
if (InType == IsInType::No)
print("::");
print("<");
for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
if (I > 0)
print(", ");
demangleGenericArg();
}
if (LeaveOpen == LeaveGenericsOpen::Yes)
return true;
else
print(">");
break;
}
case 'B': {
bool IsOpen = false;
demangleBackref([&] { IsOpen = demanglePath(InType, LeaveOpen); });
return IsOpen;
}
default:
Error = true;
break;
}
return false;
}
void Demangler::demangleImplPath(IsInType InType) {
ScopedOverride<bool> SavePrint(Print, false);
parseOptionalBase62Number('s');
demanglePath(InType);
}
void Demangler::demangleGenericArg() {
if (consumeIf('L'))
printLifetime(parseBase62Number());
else if (consumeIf('K'))
demangleConst();
else
demangleType();
}
static bool parseBasicType(char C, BasicType &Type) {
switch (C) {
case 'a':
Type = BasicType::I8;
return true;
case 'b':
Type = BasicType::Bool;
return true;
case 'c':
Type = BasicType::Char;
return true;
case 'd':
Type = BasicType::F64;
return true;
case 'e':
Type = BasicType::Str;
return true;
case 'f':
Type = BasicType::F32;
return true;
case 'h':
Type = BasicType::U8;
return true;
case 'i':
Type = BasicType::ISize;
return true;
case 'j':
Type = BasicType::USize;
return true;
case 'l':
Type = BasicType::I32;
return true;
case 'm':
Type = BasicType::U32;
return true;
case 'n':
Type = BasicType::I128;
return true;
case 'o':
Type = BasicType::U128;
return true;
case 'p':
Type = BasicType::Placeholder;
return true;
case 's':
Type = BasicType::I16;
return true;
case 't':
Type = BasicType::U16;
return true;
case 'u':
Type = BasicType::Unit;
return true;
case 'v':
Type = BasicType::Variadic;
return true;
case 'x':
Type = BasicType::I64;
return true;
case 'y':
Type = BasicType::U64;
return true;
case 'z':
Type = BasicType::Never;
return true;
default:
return false;
}
}
void Demangler::printBasicType(BasicType Type) {
switch (Type) {
case BasicType::Bool:
print("bool");
break;
case BasicType::Char:
print("char");
break;
case BasicType::I8:
print("i8");
break;
case BasicType::I16:
print("i16");
break;
case BasicType::I32:
print("i32");
break;
case BasicType::I64:
print("i64");
break;
case BasicType::I128:
print("i128");
break;
case BasicType::ISize:
print("isize");
break;
case BasicType::U8:
print("u8");
break;
case BasicType::U16:
print("u16");
break;
case BasicType::U32:
print("u32");
break;
case BasicType::U64:
print("u64");
break;
case BasicType::U128:
print("u128");
break;
case BasicType::USize:
print("usize");
break;
case BasicType::F32:
print("f32");
break;
case BasicType::F64:
print("f64");
break;
case BasicType::Str:
print("str");
break;
case BasicType::Placeholder:
print("_");
break;
case BasicType::Unit:
print("()");
break;
case BasicType::Variadic:
print("...");
break;
case BasicType::Never:
print("!");
break;
}
}
void Demangler::demangleType() {
if (Error || RecursionLevel >= MaxRecursionLevel) {
Error = true;
return;
}
ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
size_t Start = Position;
char C = consume();
BasicType Type;
if (parseBasicType(C, Type))
return printBasicType(Type);
switch (C) {
case 'A':
print("[");
demangleType();
print("; ");
demangleConst();
print("]");
break;
case 'S':
print("[");
demangleType();
print("]");
break;
case 'T': {
print("(");
size_t I = 0;
for (; !Error && !consumeIf('E'); ++I) {
if (I > 0)
print(", ");
demangleType();
}
if (I == 1)
print(",");
print(")");
break;
}
case 'R':
case 'Q':
print('&');
if (consumeIf('L')) {
if (auto Lifetime = parseBase62Number()) {
printLifetime(Lifetime);
print(' ');
}
}
if (C == 'Q')
print("mut ");
demangleType();
break;
case 'P':
print("*const ");
demangleType();
break;
case 'O':
print("*mut ");
demangleType();
break;
case 'F':
demangleFnSig();
break;
case 'D':
demangleDynBounds();
if (consumeIf('L')) {
if (auto Lifetime = parseBase62Number()) {
print(" + ");
printLifetime(Lifetime);
}
} else {
Error = true;
}
break;
case 'B':
demangleBackref([&] { demangleType(); });
break;
default:
Position = Start;
demanglePath(IsInType::Yes);
break;
}
}
void Demangler::demangleFnSig() {
ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
demangleOptionalBinder();
if (consumeIf('U'))
print("unsafe ");
if (consumeIf('K')) {
print("extern \"");
if (consumeIf('C')) {
print("C");
} else {
Identifier Ident = parseIdentifier();
if (Ident.Punycode)
Error = true;
for (char C : Ident.Name) {
if (C == '_')
C = '-';
print(C);
}
}
print("\" ");
}
print("fn(");
for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
if (I > 0)
print(", ");
demangleType();
}
print(")");
if (consumeIf('u')) {
} else {
print(" -> ");
demangleType();
}
}
void Demangler::demangleDynBounds() {
ScopedOverride<size_t> SaveBoundLifetimes(BoundLifetimes, BoundLifetimes);
print("dyn ");
demangleOptionalBinder();
for (size_t I = 0; !Error && !consumeIf('E'); ++I) {
if (I > 0)
print(" + ");
demangleDynTrait();
}
}
void Demangler::demangleDynTrait() {
bool IsOpen = demanglePath(IsInType::Yes, LeaveGenericsOpen::Yes);
while (!Error && consumeIf('p')) {
if (!IsOpen) {
IsOpen = true;
print('<');
} else {
print(", ");
}
print(parseIdentifier().Name);
print(" = ");
demangleType();
}
if (IsOpen)
print(">");
}
void Demangler::demangleOptionalBinder() {
uint64_t Binder = parseOptionalBase62Number('G');
if (Error || Binder == 0)
return;
if (Binder >= Input.size() - BoundLifetimes) {
Error = true;
return;
}
print("for<");
for (size_t I = 0; I != Binder; ++I) {
BoundLifetimes += 1;
if (I > 0)
print(", ");
printLifetime(1);
}
print("> ");
}
void Demangler::demangleConst() {
if (Error || RecursionLevel >= MaxRecursionLevel) {
Error = true;
return;
}
ScopedOverride<size_t> SaveRecursionLevel(RecursionLevel, RecursionLevel + 1);
char C = consume();
BasicType Type;
if (parseBasicType(C, Type)) {
switch (Type) {
case BasicType::I8:
case BasicType::I16:
case BasicType::I32:
case BasicType::I64:
case BasicType::I128:
case BasicType::ISize:
case BasicType::U8:
case BasicType::U16:
case BasicType::U32:
case BasicType::U64:
case BasicType::U128:
case BasicType::USize:
demangleConstInt();
break;
case BasicType::Bool:
demangleConstBool();
break;
case BasicType::Char:
demangleConstChar();
break;
case BasicType::Placeholder:
print('_');
break;
default:
Error = true;
break;
}
} else if (C == 'B') {
demangleBackref([&] { demangleConst(); });
} else {
Error = true;
}
}
void Demangler::demangleConstInt() {
if (consumeIf('n'))
print('-');
StringView HexDigits;
uint64_t Value = parseHexNumber(HexDigits);
if (HexDigits.size() <= 16) {
printDecimalNumber(Value);
} else {
print("0x");
print(HexDigits);
}
}
void Demangler::demangleConstBool() {
StringView HexDigits;
parseHexNumber(HexDigits);
if (HexDigits == "0")
print("false");
else if (HexDigits == "1")
print("true");
else
Error = true;
}
static bool isAsciiPrintable(uint64_t CodePoint) {
return 0x20 <= CodePoint && CodePoint <= 0x7e;
}
void Demangler::demangleConstChar() {
StringView HexDigits;
uint64_t CodePoint = parseHexNumber(HexDigits);
if (Error || HexDigits.size() > 6) {
Error = true;
return;
}
print("'");
switch (CodePoint) {
case '\t':
print(R"(\t)");
break;
case '\r':
print(R"(\r)");
break;
case '\n':
print(R"(\n)");
break;
case '\\':
print(R"(\\)");
break;
case '"':
print(R"(")");
break;
case '\'':
print(R"(\')");
break;
default:
if (isAsciiPrintable(CodePoint)) {
char C = CodePoint;
print(C);
} else {
print(R"(\u{)");
print(HexDigits);
print('}');
}
break;
}
print('\'');
}
Identifier Demangler::parseIdentifier() {
bool Punycode = consumeIf('u');
uint64_t Bytes = parseDecimalNumber();
consumeIf('_');
if (Error || Bytes > Input.size() - Position) {
Error = true;
return {};
}
StringView S = Input.substr(Position, Bytes);
Position += Bytes;
if (!std::all_of(S.begin(), S.end(), isValid)) {
Error = true;
return {};
}
return {S, Punycode};
}
uint64_t Demangler::parseOptionalBase62Number(char Tag) {
if (!consumeIf(Tag))
return 0;
uint64_t N = parseBase62Number();
if (Error || !addAssign(N, 1))
return 0;
return N;
}
uint64_t Demangler::parseBase62Number() {
if (consumeIf('_'))
return 0;
uint64_t Value = 0;
while (true) {
uint64_t Digit;
char C = consume();
if (C == '_') {
break;
} else if (isDigit(C)) {
Digit = C - '0';
} else if (isLower(C)) {
Digit = 10 + (C - 'a');
} else if (isUpper(C)) {
Digit = 10 + 26 + (C - 'A');
} else {
Error = true;
return 0;
}
if (!mulAssign(Value, 62))
return 0;
if (!addAssign(Value, Digit))
return 0;
}
if (!addAssign(Value, 1))
return 0;
return Value;
}
uint64_t Demangler::parseDecimalNumber() {
char C = look();
if (!isDigit(C)) {
Error = true;
return 0;
}
if (C == '0') {
consume();
return 0;
}
uint64_t Value = 0;
while (isDigit(look())) {
if (!mulAssign(Value, 10)) {
Error = true;
return 0;
}
uint64_t D = consume() - '0';
if (!addAssign(Value, D))
return 0;
}
return Value;
}
uint64_t Demangler::parseHexNumber(StringView &HexDigits) {
size_t Start = Position;
uint64_t Value = 0;
if (!isHexDigit(look()))
Error = true;
if (consumeIf('0')) {
if (!consumeIf('_'))
Error = true;
} else {
while (!Error && !consumeIf('_')) {
char C = consume();
Value *= 16;
if (isDigit(C))
Value += C - '0';
else if ('a' <= C && C <= 'f')
Value += 10 + (C - 'a');
else
Error = true;
}
}
if (Error) {
HexDigits = StringView();
return 0;
}
size_t End = Position - 1;
assert(Start < End);
HexDigits = Input.substr(Start, End - Start);
return Value;
}
void Demangler::print(char C) {
if (Error || !Print)
return;
Output += C;
}
void Demangler::print(StringView S) {
if (Error || !Print)
return;
Output += S;
}
void Demangler::printDecimalNumber(uint64_t N) {
if (Error || !Print)
return;
Output << N;
}
void Demangler::printLifetime(uint64_t Index) {
if (Index == 0) {
print("'_");
return;
}
if (Index - 1 >= BoundLifetimes) {
Error = true;
return;
}
uint64_t Depth = BoundLifetimes - Index;
print('\'');
if (Depth < 26) {
char C = 'a' + Depth;
print(C);
} else {
print('z');
printDecimalNumber(Depth - 26 + 1);
}
}
static inline bool decodePunycodeDigit(char C, size_t &Value) {
if (isLower(C)) {
Value = C - 'a';
return true;
}
if (isDigit(C)) {
Value = 26 + (C - '0');
return true;
}
return false;
}
static void removeNullBytes(OutputBuffer &Output, size_t StartIdx) {
char *Buffer = Output.getBuffer();
char *Start = Buffer + StartIdx;
char *End = Buffer + Output.getCurrentPosition();
Output.setCurrentPosition(std::remove(Start, End, '\0') - Buffer);
}
static inline bool encodeUTF8(size_t CodePoint, char *Output) {
if (0xD800 <= CodePoint && CodePoint <= 0xDFFF)
return false;
if (CodePoint <= 0x7F) {
Output[0] = CodePoint;
return true;
}
if (CodePoint <= 0x7FF) {
Output[0] = 0xC0 | ((CodePoint >> 6) & 0x3F);
Output[1] = 0x80 | (CodePoint & 0x3F);
return true;
}
if (CodePoint <= 0xFFFF) {
Output[0] = 0xE0 | (CodePoint >> 12);
Output[1] = 0x80 | ((CodePoint >> 6) & 0x3F);
Output[2] = 0x80 | (CodePoint & 0x3F);
return true;
}
if (CodePoint <= 0x10FFFF) {
Output[0] = 0xF0 | (CodePoint >> 18);
Output[1] = 0x80 | ((CodePoint >> 12) & 0x3F);
Output[2] = 0x80 | ((CodePoint >> 6) & 0x3F);
Output[3] = 0x80 | (CodePoint & 0x3F);
return true;
}
return false;
}
static bool decodePunycode(StringView Input, OutputBuffer &Output) {
size_t OutputSize = Output.getCurrentPosition();
size_t InputIdx = 0;
size_t DelimiterPos = StringView::npos;
for (size_t I = 0; I != Input.size(); ++I)
if (Input[I] == '_')
DelimiterPos = I;
if (DelimiterPos != StringView::npos) {
for (; InputIdx != DelimiterPos; ++InputIdx) {
char C = Input[InputIdx];
if (!isValid(C))
return false;
char UTF8[4] = {C};
Output += StringView(UTF8, UTF8 + 4);
}
++InputIdx;
}
size_t Base = 36;
size_t Skew = 38;
size_t Bias = 72;
size_t N = 0x80;
size_t TMin = 1;
size_t TMax = 26;
size_t Damp = 700;
auto Adapt = [&](size_t Delta, size_t NumPoints) {
Delta /= Damp;
Delta += Delta / NumPoints;
Damp = 2;
size_t K = 0;
while (Delta > (Base - TMin) * TMax / 2) {
Delta /= Base - TMin;
K += Base;
}
return K + (((Base - TMin + 1) * Delta) / (Delta + Skew));
};
for (size_t I = 0; InputIdx != Input.size(); I += 1) {
size_t OldI = I;
size_t W = 1;
size_t Max = std::numeric_limits<size_t>::max();
for (size_t K = Base; true; K += Base) {
if (InputIdx == Input.size())
return false;
char C = Input[InputIdx++];
size_t Digit = 0;
if (!decodePunycodeDigit(C, Digit))
return false;
if (Digit > (Max - I) / W)
return false;
I += Digit * W;
size_t T;
if (K <= Bias)
T = TMin;
else if (K >= Bias + TMax)
T = TMax;
else
T = K - Bias;
if (Digit < T)
break;
if (W > Max / (Base - T))
return false;
W *= (Base - T);
}
size_t NumPoints = (Output.getCurrentPosition() - OutputSize) / 4 + 1;
Bias = Adapt(I - OldI, NumPoints);
if (I / NumPoints > Max - N)
return false;
N += I / NumPoints;
I = I % NumPoints;
char UTF8[4] = {};
if (!encodeUTF8(N, UTF8))
return false;
Output.insert(OutputSize + I * 4, UTF8, 4);
}
removeNullBytes(Output, OutputSize);
return true;
}
void Demangler::printIdentifier(Identifier Ident) {
if (Error || !Print)
return;
if (Ident.Punycode) {
if (!decodePunycode(Ident.Name, Output))
Error = true;
} else {
print(Ident.Name);
}
}
char Demangler::look() const {
if (Error || Position >= Input.size())
return 0;
return Input[Position];
}
char Demangler::consume() {
if (Error || Position >= Input.size()) {
Error = true;
return 0;
}
return Input[Position++];
}
bool Demangler::consumeIf(char Prefix) {
if (Error || Position >= Input.size() || Input[Position] != Prefix)
return false;
Position += 1;
return true;
}
bool Demangler::addAssign(uint64_t &A, uint64_t B) {
if (A > std::numeric_limits<uint64_t>::max() - B) {
Error = true;
return false;
}
A += B;
return true;
}
bool Demangler::mulAssign(uint64_t &A, uint64_t B) {
if (B != 0 && A > std::numeric_limits<uint64_t>::max() / B) {
Error = true;
return false;
}
A *= B;
return true;
}