| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- namespace Ryujinx.HLE.OsHle.Diagnostics
- {
- static class Demangler
- {
- private static readonly Dictionary<string, string> BuiltinTypes = new Dictionary<string, string>
- {
- { "v", "void" },
- { "w", "wchar_t" },
- { "b", "bool" },
- { "c", "char" },
- { "a", "signed char" },
- { "h", "unsigned char" },
- { "s", "short" },
- { "t", "unsigned short" },
- { "i", "int" },
- { "j", "unsigned int" },
- { "l", "long" },
- { "m", "unsigned long" },
- { "x", "long long" },
- { "y", "unsigned long long" },
- { "n", "__int128" },
- { "o", "unsigned __int128" },
- { "f", "float" },
- { "d", "double" },
- { "e", "long double" },
- { "g", "__float128" },
- { "z", "..." },
- { "Dd", "__iec559_double" },
- { "De", "__iec559_float128" },
- { "Df", "__iec559_float" },
- { "Dh", "__iec559_float16" },
- { "Di", "char32_t" },
- { "Ds", "char16_t" },
- { "Da", "decltype(auto)" },
- { "Dn", "std::nullptr_t" },
- };
- private static readonly Dictionary<string, string> SubstitutionExtra = new Dictionary<string, string>
- {
- {"Sa", "std::allocator"},
- {"Sb", "std::basic_string"},
- {"Ss", "std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>"},
- {"Si", "std::basic_istream<char, ::std::char_traits<char>>"},
- {"So", "std::basic_ostream<char, ::std::char_traits<char>>"},
- {"Sd", "std::basic_iostream<char, ::std::char_traits<char>>"}
- };
- private static int FromBase36(string encoded)
- {
- string base36 = "0123456789abcdefghijklmnopqrstuvwxyz";
- char[] reversedEncoded = encoded.ToLower().ToCharArray().Reverse().ToArray();
- int result = 0;
- for (int i = 0; i < reversedEncoded.Length; i++)
- {
- char c = reversedEncoded[i];
- int value = base36.IndexOf(c);
- if (value == -1)
- return -1;
- result += value * (int)Math.Pow(36, i);
- }
- return result;
- }
- private static string GetCompressedValue(string compression, List<string> compressionData, out int pos)
- {
- string res = null;
- bool canHaveUnqualifiedName = false;
- pos = -1;
- if (compressionData.Count == 0 || !compression.StartsWith("S"))
- return null;
- if (compression.Length >= 2 && SubstitutionExtra.TryGetValue(compression.Substring(0, 2), out string substitutionValue))
- {
- pos = 1;
- res = substitutionValue;
- compression = compression.Substring(2);
- }
- else if (compression.StartsWith("St"))
- {
- pos = 1;
- canHaveUnqualifiedName = true;
- res = "std";
- compression = compression.Substring(2);
- }
- else if (compression.StartsWith("S_"))
- {
- pos = 1;
- res = compressionData[0];
- canHaveUnqualifiedName = true;
- compression = compression.Substring(2);
- }
- else
- {
- int id = -1;
- int underscorePos = compression.IndexOf('_');
- if (underscorePos == -1)
- return null;
- string partialId = compression.Substring(1, underscorePos - 1);
- id = FromBase36(partialId);
- if (id == -1 || compressionData.Count <= (id + 1))
- {
- return null;
- }
- res = compressionData[id + 1];
- pos = partialId.Length + 1;
- canHaveUnqualifiedName= true;
- compression = compression.Substring(pos);
- }
- if (res != null)
- {
- if (canHaveUnqualifiedName)
- {
- List<string> type = ReadName(compression, compressionData, out int endOfNameType);
- if (endOfNameType != -1 && type != null)
- {
- pos += endOfNameType;
- res = res + "::" + type[type.Count - 1];
- }
- }
- }
- return res;
- }
- private static List<string> ReadName(string mangled, List<string> compressionData, out int pos, bool isNested = true)
- {
- List<string> res = new List<string>();
- string charCountString = null;
- int charCount = 0;
- int i;
- pos = -1;
- for (i = 0; i < mangled.Length; i++)
- {
- char chr = mangled[i];
- if (charCountString == null)
- {
- if (ReadCVQualifiers(chr) != null)
- {
- continue;
- }
- if (chr == 'S')
- {
- string data = GetCompressedValue(mangled.Substring(i), compressionData, out pos);
- if (pos == -1)
- {
- return null;
- }
- if (res.Count == 0)
- res.Add(data);
- else
- res.Add(res[res.Count - 1] + "::" + data);
- i += pos;
- if (i < mangled.Length && mangled[i] == 'E')
- {
- break;
- }
- continue;
- }
- else if (chr == 'E')
- {
- break;
- }
- }
- if (Char.IsDigit(chr))
- {
- charCountString += chr;
- }
- else
- {
- if (!int.TryParse(charCountString, out charCount))
- {
- return null;
- }
- string demangledPart = mangled.Substring(i, charCount);
- if (res.Count == 0)
- res.Add(demangledPart);
- else
- res.Add(res[res.Count - 1] + "::" + demangledPart);
- i = i + charCount - 1;
- charCount = 0;
- charCountString = null;
- if (!isNested)
- break;
- }
- }
- if (res.Count == 0)
- {
- return null;
- }
- pos = i;
- return res;
- }
- private static string ReadBuiltinType(string mangledType, out int pos)
- {
- string res = null;
- string possibleBuiltinType;
- pos = -1;
- possibleBuiltinType = mangledType[0].ToString();
- if (!BuiltinTypes.TryGetValue(possibleBuiltinType, out res))
- {
- if (mangledType.Length >= 2)
- {
- // Try to match the first 2 chars if the first call failed
- possibleBuiltinType = mangledType.Substring(0, 2);
- BuiltinTypes.TryGetValue(possibleBuiltinType, out res);
- }
- }
- if (res != null)
- pos = possibleBuiltinType.Length;
- return res;
- }
- private static string ReadCVQualifiers(char qualifier)
- {
- if (qualifier == 'r')
- return "restricted";
- else if (qualifier == 'V')
- return "volatile";
- else if (qualifier == 'K')
- return "const";
- return null;
- }
- private static string ReadRefQualifiers(char qualifier)
- {
- if (qualifier == 'R')
- return "&";
- else if (qualifier == 'O')
- return "&&";
- return null;
- }
- private static string ReadSpecialQualifiers(char qualifier)
- {
- if (qualifier == 'P')
- return "*";
- else if (qualifier == 'C')
- return "complex";
- else if (qualifier == 'G')
- return "imaginary";
- return null;
- }
- private static List<string> ReadParameters(string mangledParams, List<string> compressionData, out int pos)
- {
- List<string> res = new List<string>();
- List<string> refQualifiers = new List<string>();
- string parsedTypePart = null;
- string currentRefQualifiers = null;
- string currentBuiltinType = null;
- string currentSpecialQualifiers = null;
- string currentCompressedValue = null;
- int i = 0;
- pos = -1;
- for (i = 0; i < mangledParams.Length; i++)
- {
- if (currentBuiltinType != null)
- {
- string currentCVQualifier = String.Join(" ", refQualifiers);
- // Try to mimic the compression indexing
- if (currentRefQualifiers != null)
- {
- compressionData.Add(currentBuiltinType + currentRefQualifiers);
- }
- if (refQualifiers.Count != 0)
- {
- compressionData.Add(currentBuiltinType + " " + currentCVQualifier + currentRefQualifiers);
- }
- if (currentSpecialQualifiers != null)
- {
- compressionData.Add(currentBuiltinType + " " + currentCVQualifier + currentRefQualifiers + currentSpecialQualifiers);
- }
- if (currentRefQualifiers == null && currentCVQualifier == null && currentSpecialQualifiers == null)
- {
- compressionData.Add(currentBuiltinType);
- }
- currentBuiltinType = null;
- currentCompressedValue = null;
- currentCVQualifier = null;
- currentRefQualifiers = null;
- refQualifiers.Clear();
- currentSpecialQualifiers = null;
- }
- char chr = mangledParams[i];
- string part = mangledParams.Substring(i);
- // Try to read qualifiers
- parsedTypePart = ReadCVQualifiers(chr);
- if (parsedTypePart != null)
- {
- refQualifiers.Add(parsedTypePart);
- // need more data
- continue;
- }
- parsedTypePart = ReadRefQualifiers(chr);
- if (parsedTypePart != null)
- {
- currentRefQualifiers = parsedTypePart;
- // need more data
- continue;
- }
- parsedTypePart = ReadSpecialQualifiers(chr);
- if (parsedTypePart != null)
- {
- currentSpecialQualifiers = parsedTypePart;
- // need more data
- continue;
- }
- // TODO: extended-qualifier?
- if (part.StartsWith("S"))
- {
- parsedTypePart = GetCompressedValue(part, compressionData, out pos);
- if (pos != -1 && parsedTypePart != null)
- {
- currentCompressedValue = parsedTypePart;
- i += pos;
- res.Add(currentCompressedValue + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers);
- currentBuiltinType = null;
- currentCompressedValue = null;
- currentRefQualifiers = null;
- refQualifiers.Clear();
- currentSpecialQualifiers = null;
- continue;
- }
- pos = -1;
- return null;
- }
- else if (part.StartsWith("N"))
- {
- part = part.Substring(1);
- List<string> name = ReadName(part, compressionData, out pos);
- if (pos != -1 && name != null)
- {
- i += pos + 1;
- res.Add(name[name.Count - 1] + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers);
- currentBuiltinType = null;
- currentCompressedValue = null;
- currentRefQualifiers = null;
- refQualifiers.Clear();
- currentSpecialQualifiers = null;
- continue;
- }
- }
- // Try builting
- parsedTypePart = ReadBuiltinType(part, out pos);
- if (pos == -1)
- {
- return null;
- }
- currentBuiltinType = parsedTypePart;
- res.Add(currentBuiltinType + " " + String.Join(" ", refQualifiers) + currentRefQualifiers + currentSpecialQualifiers);
- i = i + pos -1;
- }
- pos = i;
- return res;
- }
- private static string ParseFunctionName(string mangled)
- {
- List<string> compressionData = new List<string>();
- int pos = 0;
- string res;
- bool isNested = mangled.StartsWith("N");
- // If it's start with "N" it must be a nested function name
- if (isNested)
- mangled = mangled.Substring(1);
- compressionData = ReadName(mangled, compressionData, out pos, isNested);
- if (pos == -1)
- return null;
- res = compressionData[compressionData.Count - 1];
- compressionData.Remove(res);
- mangled = mangled.Substring(pos + 1);
- // more data? maybe not a data name so...
- if (mangled != String.Empty)
- {
- List<string> parameters = ReadParameters(mangled, compressionData, out pos);
- // parameters parsing error, we return the original data to avoid information loss.
- if (pos == -1)
- return null;
- parameters = parameters.Select(outer => outer.Trim()).ToList();
- res += "(" + String.Join(", ", parameters) + ")";
- }
- return res;
- }
- public static string Parse(string originalMangled)
- {
- if (originalMangled.StartsWith("_Z"))
- {
- // We assume that we have a name (TOOD: support special names)
- string res = ParseFunctionName(originalMangled.Substring(2));
- if (res == null)
- return originalMangled;
- return res;
- }
- return originalMangled;
- }
- }
- }
|