From 289f536c9befb9f984c93e82f412ac8c3a40cde2 Mon Sep 17 00:00:00 2001 From: Thog Date: Mon, 7 May 2018 20:16:37 +0200 Subject: [PATCH] Starting a real parsing for demangler (still simple and no compression support yet) --- Ryujinx.Core/OsHle/Diagnostics/Demangle.cs | 292 ++++++++++++++++++--- Ryujinx.Core/OsHle/Process.cs | 3 +- 2 files changed, 262 insertions(+), 33 deletions(-) diff --git a/Ryujinx.Core/OsHle/Diagnostics/Demangle.cs b/Ryujinx.Core/OsHle/Diagnostics/Demangle.cs index ee51c9e040..c64ee0464e 100644 --- a/Ryujinx.Core/OsHle/Diagnostics/Demangle.cs +++ b/Ryujinx.Core/OsHle/Diagnostics/Demangle.cs @@ -1,60 +1,288 @@ using System; +using System.Collections; +using System.Collections.Generic; namespace Ryujinx.Core.OsHle.Diagnostics { - static class Demangle + public static class Demangle { - public static string ReadName(string mangled) + /* + ::= 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, __int64 + ::= y # unsigned long long, __int64 + ::= n # __int128 + ::= o # unsigned __int128 + ::= f # float + ::= d # double + ::= e # long double, __float80 + ::= g # __float128 + ::= z # ellipsis + ::= Dd # IEEE 754r decimal floating point (64 bits) + ::= De # IEEE 754r decimal floating point (128 bits) + ::= Df # IEEE 754r decimal floating point (32 bits) + ::= Dh # IEEE 754r half-precision floating point (16 bits) + ::= DF _ # ISO/IEC TS 18661 binary floating point type _FloatN (N bits) + ::= Di # char32_t + ::= Ds # char16_t + ::= Da # auto + ::= Dc # decltype(auto) + ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) + */ + private static readonly Dictionary BuiltinTypes = new Dictionary { - string result = null; + { "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, __int64" }, + { "y", "unsigned long long, __int64" }, + { "n", "__int128" }, + { "o", "unsigned __int128" }, + { "f", "float" }, + { "d", "double" }, + { "e", "long double, __float80" }, + { "g", "__float128" }, + { "z", "ellipsis" }, + { "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" }, + }; + public static List ReadName(string mangled, out int pos, List compressionData) + { + List res = new List(); string charCountTemp = null; int charCount = 0; + int i; - foreach (var chr in mangled) + pos = -1; + for (i = 0; i < mangled.Length; i++) { - if (charCount == 0) + char chr = mangled[i]; + if (charCountTemp == null) { - if (charCountTemp == null) + if (ReadCVQualifiers(chr) != null) { - if (chr == 'r' || chr == 'V' || chr == 'K') - { - continue; - } - if (chr == 'E') - { - break; - } + continue; } - if (Char.IsDigit(chr)) + if (chr == 'E') { - charCountTemp += chr; - } - else - { - if (!int.TryParse(charCountTemp, out charCount)) - { - return mangled; - } - result += chr; - charCount--; - charCountTemp = null; + break; } } + if (Char.IsDigit(chr)) + { + charCountTemp += chr; + } else { - result += chr; - charCount--; - if (charCount == 0) + if (!int.TryParse(charCountTemp, out charCount)) { - result += "::"; + 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; + charCountTemp = null; } } - if (result == null) + if (res.Count == 0) + { + return null; + } + pos = i; + return res; + } + + public static string ReadBuiltinType(string mangledType, out int pos) + { + string res = null; + string temp; + pos = -1; + temp = mangledType[0].ToString(); + if (!BuiltinTypes.TryGetValue(temp, out res)) + { + temp = mangledType.Substring(0, 2); + BuiltinTypes.TryGetValue(temp, out res); + } + if (res != null) + pos = temp.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"; + else if (qualifier == 'R') + return "&"; + else if (qualifier == 'O') + return "&&"; + 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; + } + + public static List ReadParameters(string mangledParams, out int pos) + { + List res = new List(); + int i = 0; + pos = -1; + + string temp = null; + string temp2 = null; + for (i = 0; i < mangledParams.Length; i++) + { + char chr = mangledParams[i]; + string part = mangledParams.Substring(i); + + // Try to read qualifiers + temp2 = ReadCVQualifiers(chr); + if (temp2 != null) + { + temp = temp2 + " " + temp; + continue; + } + + temp2 = ReadRefQualifiers(chr); + if (temp2 != null) + { + temp = temp + temp2; + continue; + } + + temp2 = ReadSpecialQualifiers(chr); + if (temp2 != null) + { + Console.WriteLine(temp); + temp = temp + temp2; + continue; + } + + // TODO: extended-qualifier? + + // Try builting + temp2 = ReadBuiltinType(part, out pos); + if (pos == -1) + { + return null; + } + if (temp != null) + temp = temp2 + " " + temp; + else + temp = temp2; + res.Add(temp); + temp = null; + i = i + pos -1; + } + pos = i; + return res; + } + + public static string ReadNameString(string mangled, out int pos) + { + List name = ReadName(mangled, out pos, new List()); + if (pos == -1 || name == null || name.Count == 0) { return mangled; } - return result.Substring(0, result.Length - 2); + foreach (var entry in name) + { + Console.WriteLine(entry); + } + + return name[name.Count - 1]; + } + + /** + ::= _Z + ::= + ::= + ::= + */ + public static string Parse(string mangled) + { + Console.WriteLine("Mangled: " + mangled); + List compressionData = new List(); + string res = null; + int pos = 0; + + // We asume that we start with a function name + // TODO: support special names + if (mangled.StartsWith("_ZN")) + { + mangled = mangled.Substring(3); + compressionData = ReadName(mangled, out pos, compressionData); + if (pos == -1) + return mangled; + 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 parameters = ReadParameters(mangled, out pos); + // parameters parsing error, we return the original data to avoid information loss. + if (pos == -1) + return mangled; + res += "("; + res += String.Join(", ", parameters); + res += ")"; + } + return res; + } + return mangled; } } } \ No newline at end of file diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs index 4d7506421e..15e394efb3 100644 --- a/Ryujinx.Core/OsHle/Process.cs +++ b/Ryujinx.Core/OsHle/Process.cs @@ -307,7 +307,8 @@ namespace Ryujinx.Core.OsHle } else if (SubName.StartsWith("_ZN")) { - SubName = Demangle.ReadName(SubName.Substring(3)); + int i = 0; + SubName = Demangle.ReadNameString(SubName.Substring(3), out i); } Trace.AppendLine(" " + SubName + " (" + GetNsoNameAndAddress(Position) + ")");