#include "BfDemangler.h" USING_NS_BF; static char SafeGetChar(const StringImpl& str, int idx) { if (idx >= (int)str.length()) return '!'; return str[idx]; } DemangleBase::DemangleBase() { mCurIdx = 0; mFailed = false; mLanguage = DbgLanguage_Unknown; mInArgs = false; mBeefFixed = false; } bool DemangleBase::Failed() { //BF_DBG_FATAL("DwDemangler::Failed"); mFailed = true; return false; } void DemangleBase::Require(bool result) { //BF_ASSERT(result); if (!result) { mFailed = true; } } ////////////////////////////////////////////////////////////////////////// DwDemangler::DwDemangler() { mOmitSubstituteAdd = false; mIsFirstName = true; mTemplateDepth = 0; mCaptureTargetType = false; mFunctionPopSubstitute = false; mRawDemangle = false; } #define RETURN_STR(strVal) do { outName = strVal; return true; } while(false) bool DwDemangler::DemangleBuiltinType(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); switch (firstChar) { case 'v': RETURN_STR("void"); case 'w': RETURN_STR("wchar_t"); case 'b': RETURN_STR("bool"); case 'a': if (mLanguage == DbgLanguage_Beef) RETURN_STR("int8"); else RETURN_STR("sbyte"); case 'h': if (mLanguage == DbgLanguage_Beef) RETURN_STR("uint8"); else RETURN_STR("byte"); case 's': RETURN_STR("short"); case 't': RETURN_STR("ushort"); case 'i': if (mLanguage == DbgLanguage_Beef) RETURN_STR("int32"); else RETURN_STR("int"); case 'j': if (mLanguage == DbgLanguage_Beef) RETURN_STR("uint32"); else RETURN_STR("uint"); case 'x': RETURN_STR("long"); case 'l': if (mLanguage == DbgLanguage_Beef) RETURN_STR("int32"); else RETURN_STR("int"); case 'm': if (mLanguage == DbgLanguage_Beef) RETURN_STR("uint32"); else RETURN_STR("uint"); case 'y': RETURN_STR("ulong"); case 'c': if (mLanguage == DbgLanguage_Beef) RETURN_STR("char8"); else RETURN_STR("char"); case 'f': RETURN_STR("float"); case 'd': RETURN_STR("double"); case 'n': RETURN_STR("__int128"); case 'o': RETURN_STR("__uint128"); case 'e': RETURN_STR("__float80"); case 'g': RETURN_STR("__float128"); case 'z': RETURN_STR("..."); case 'D': { char nextChar = SafeGetChar(mMangledName, mCurIdx++); switch (nextChar) { case 'i': RETURN_STR("char32"); case 's': RETURN_STR("char16"); case 'a': RETURN_STR("auto"); case 'c': RETURN_STR("decltype(auto)"); case 'n': RETURN_STR("std::nullptr_t"); default: RETURN_STR("?"); } } break; default: mCurIdx--; break; } return false; } bool DwDemangler::DemangleArrayType(StringImpl& outName) { //TODO: /*auto firstChar = SafeGetChar(mMangledName, mCurIdx++); switch (firstChar) { case 'A': { } break; default: mCurIdx--; }*/ return false; } bool DwDemangler::DemangleClassEnumType(StringImpl& outName) { if (DemangleName(outName)) return true; //TODO: 'Ts', 'Tu', 'Te' return false; } bool DwDemangler::DemangleFunction(StringImpl& outName) { bool wantsReturnValue = false; //String outName; bool hasTemplateArgs; Require(DemangleName(outName, &hasTemplateArgs)); mIsFirstName = false; if (hasTemplateArgs) wantsReturnValue = true; // Pop either function name or template args if (mSubstituteList.size() > 0) mSubstituteList.pop_back(); if (mCaptureTargetType) { int lastAt = (int)outName.LastIndexOf('@'); if (lastAt != -1) { DwDemangler subDemangler; outName.Remove(0, lastAt + 1); outName = subDemangler.Demangle(outName); return true; } int lastDot = (int)outName.LastIndexOf('.'); if (lastDot != -1) outName.RemoveToEnd(lastDot); return true; } // New if (mFunctionPopSubstitute) { BF_ASSERT(mSubstituteList.size() > 0); if (mSubstituteList.size() > 0) mSubstituteList.pop_back(); mFunctionPopSubstitute = false; } if (mCurIdx < (int) mMangledName.length()) { //TODO: Needed? Caused a crash. mSubstituteList.pop_back(); // Remove method name int atPos = (int)outName.LastIndexOf('@'); if (atPos != -1) { int dotPos = (int)outName.LastIndexOf('.', atPos); if (dotPos != -1) { StringT<256> prefix = outName.Substring(dotPos + 1, atPos - dotPos - 1); if ((prefix == "get") || (prefix == "set")) { outName = outName.Substring(0, dotPos + 1) + outName.Substring(atPos + 1) + " " + prefix; return true; } } } outName += "("; bool needsComma = false; for (int paramIdx = 0; mCurIdx < (int)mMangledName.length(); paramIdx++) { if (SafeGetChar(mMangledName, mCurIdx) == 'E') break; if (needsComma) outName += ", "; StringT<256> paramType; Require(DemangleType(paramType)); bool atEnd = mCurIdx >= (int) mMangledName.length(); if ((paramIdx == 0) && (wantsReturnValue)) { outName = paramType + " " + outName; } else { if ((paramType == "void") && (paramIdx == 0) && (atEnd)) break; outName += paramType; needsComma = true; } if (mFailed) break; } outName += ")"; } return true; } bool DwDemangler::DemangleLocalName(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); if (firstChar == 'Z') { if (SafeGetChar(mMangledName, mCurIdx) == 'L') // Literal (?) mCurIdx++; DemangleFunction(outName); auto endChar = SafeGetChar(mMangledName, mCurIdx++); if (endChar != 'E') return false; endChar = SafeGetChar(mMangledName, mCurIdx++); if (endChar == 's') { // } else { mCurIdx--; StringT<256> entityName; Require(DemangleName(entityName)); if (mLanguage == DbgLanguage_Beef) outName += "." + entityName; else outName += "::" + entityName; } endChar = SafeGetChar(mMangledName, mCurIdx++); if (endChar == '_') { // } else { mCurIdx--; } BF_ASSERT(mSubstituteList.size() > 0); if (mSubstituteList.size() >= 2) { mSubstituteList.pop_back(); mSubstituteList[mSubstituteList.size() - 1] = outName; } return true; } mCurIdx--; return false; } bool DwDemangler::DemangleType(StringImpl& outName) { StringT<256> cvQualifiers; if (DemangleCVQualifiers(cvQualifiers)) { Require(DemangleType(outName)); outName = cvQualifiers + " " + outName; mSubstituteList.push_back(outName); return true; } auto firstChar = SafeGetChar(mMangledName, mCurIdx++); switch (firstChar) { case 'D': { auto nextChar = SafeGetChar(mMangledName, mCurIdx++); if (nextChar == 'p') { Require(DemangleType(outName)); return true; } mCurIdx--; } case 'P': if (DemangleFunctionType(outName)) { mSubstituteList.push_back(outName); return true; } if (DemangleType(outName)) { outName = outName + "*"; mSubstituteList.push_back(outName); return true; } break; case 'R': if (DemangleType(outName)) { outName = outName + "&"; mSubstituteList.push_back(outName); return true; } break; case 'O': if (DemangleType(outName)) { if (outName[outName.length() - 1] != '&') outName = outName + "&&"; mSubstituteList.push_back(outName); return true; } break; case 'U': { StringT<256> modName; Require(DemangleUnqualifiedName(modName)); Require(DemangleType(outName)); if (modName[0] == '@') outName = outName + " " + modName.Substring(1); else outName = modName + " " + outName; return true; } break; //TODO: 'C', 'G', 'U' default: mCurIdx--; break; } if (DemangleBuiltinType(outName)) return true; if (DemangleFunctionType(outName)) return true; if (DemangleSubstitution(outName)) { StringT<256> templateArgs; if (DemangleTemplateArgs(templateArgs)) { outName += templateArgs; mSubstituteList.push_back(outName); } return true; } if (DemangleClassEnumType(outName)) return true; //TODO: DemangleArrayType //TODO: DemanglePointerToMemberType if (DemangleTemplateParam(outName)) return true; //TODO: TemplateTemplateParam //TODO: DeclType return false; } bool DwDemangler::DemangleFunctionType(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); if (firstChar == 'F') { StringT<256> returnType; Require(DemangleType(returnType)); outName = returnType + " (*)("; for (int paramNum = 0; true; paramNum++) { if (DemangleEnd()) break; if (paramNum > 0) outName += ", "; StringT<256> paramType; Require(DemangleType(paramType)); outName += paramType; } outName += ")"; return true; } mCurIdx--; return false; } bool DwDemangler::DemangleNestedName(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); switch (firstChar) { case 'N': { } break; } mCurIdx--; return false; } bool DwDemangler::DemangleCVQualifiers(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); switch (firstChar) { case 'r': RETURN_STR("restrict"); case 'V': RETURN_STR("volatile"); case 'K': RETURN_STR("const"); } mCurIdx--; return false; } bool DwDemangler::DemangleRefQualifier(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); switch (firstChar) { case 'R': RETURN_STR("&"); case 'O': RETURN_STR("&&"); } mCurIdx--; return false; } bool DwDemangler::DemangleOperatorName(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); StringT<64> opCode; opCode += firstChar; opCode += SafeGetChar(mMangledName, mCurIdx++); StringT<64> opName; if (opCode == "nw") opName = " new"; else if (opCode == "na") opName = " new[]"; else if (opCode == "dl") opName = " delete"; else if (opCode == "da") opName = " delete[]"; else if (opCode == "pl") opName = "+"; else if (opCode == "mi") opName = "-"; else if (opCode == "ml") opName = "*"; else if (opCode == "dv") opName = "/"; else if (opCode == "rm") opName = "%"; else if (opCode == "an") opName = "&"; else if (opCode == "or") opName = "|"; else if (opCode == "eo") opName = "^"; else if (opCode == "aS") opName = "="; else if (opCode == "pL") opName = "+="; else if (opCode == "mI") opName = "-="; else if (opCode == "mL") opName = "*="; else if (opCode == "dV") opName = "/="; else if (opCode == "rM") opName = "%="; else if (opCode == "aN") opName = "&="; else if (opCode == "oR") opName = "|="; else if (opCode == "eO") opName = "^="; else if (opCode == "ls") opName = "<<"; else if (opCode == "rs") opName = ">>"; else if (opCode == "eq") opName = "=="; else if (opCode == "ne") opName = "!="; else if (opCode == "lt") opName = "<"; else if (opCode == "gt") opName = ">"; else if (opCode == "ge") opName = ">="; else if (opCode == "le") opName = "<="; else if (opCode == "aa") opName = "&&"; else if (opCode == "oo") opName = "||"; else if (opCode == "ad") opName = "&"; else if (opCode == "de") opName = "*"; else if (opCode == "ng") opName = "-"; else if (opCode == "nt") opName = "!"; else if (opCode == "ps") opName = "+"; else if (opCode == "co") opName = "~"; else if (opCode == "pp") opName = "++"; else if (opCode == "mm") opName = "--"; else if (opCode == "cm") opName = ","; else if (opCode == "pm") opName = "->*"; else if (opCode == "pt") opName = "->"; else if (opCode == "ix") opName = "[]"; else if (opCode == "cl") opName = "()"; else if (opCode == "qu") opName = "?"; else if (opCode == "li") { opName = "\"\""; } else if (opCode == "cv") { StringT<256> typeName; Require(DemangleType(typeName)); opName = " " + typeName; } else if ((opCode == "C1") || (opCode == "C2") || (opCode == "C3")) { outName += "this"; } else if ((opCode == "D0") || (opCode == "D1") || (opCode == "D2")) { outName += "~this"; } else { mCurIdx -= 2; return false; } if (!opName.empty()) outName += "operator" + opName; //mSubstituteList.push_back(outName); return true; } bool DwDemangler::DemangleSourceName(StringImpl& outName) { auto c = SafeGetChar(mMangledName, mCurIdx); if ((c >= '0') && (c <= '9')) { int nameLen = 0; while (mCurIdx < (int) mMangledName.length()) { char c = mMangledName[mCurIdx]; if ((c >= '0') && (c <= '9')) { nameLen = (int) (c - '0') + (nameLen * 10); mCurIdx++; } else break; } for (int nameIdx = 0; ((nameIdx < nameLen) && (mCurIdx < (int) mMangledName.length())); nameIdx++) { char c = mMangledName[mCurIdx++]; outName += c; } //mSubstituteList.push_back(outName); return true; } return false; } bool DwDemangler::DemangleUnqualifiedName(StringImpl& outName) { if (DemangleOperatorName(outName)) // Also handles ctor/dtor return true; if (DemangleSourceName(outName)) return true; return false; } bool DwDemangler::DemangleEnd() { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); if (firstChar == 'E') return true; mCurIdx--; return false; } bool DwDemangler::DemangleInternalName(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); if (firstChar == 'L') { bool result = DemangleSourceName(outName); Require(result); return result; } mCurIdx--; return false; } bool DwDemangler::DemangleExprPriamry(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); if (firstChar == 'L') { StringT<256> outType; Require(DemangleType(outType)); StringT<256> value; while (true) { auto c = SafeGetChar(mMangledName, mCurIdx++); if (c == 'E') break; value += c; } if (outType == "bool") outName = (value == "0") ? "false" : "true"; else outName = value; return true; } mCurIdx--; return false; } bool DwDemangler::DemangleTemplateArg(StringImpl& outName) { if (DemangleType(outName)) return true; if (DemangleExprPriamry(outName)) return true; //TODO: Expression, Simple Expressions, Argument Pack return false; } bool DwDemangler::DemangleTemplateArgs(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); if (firstChar == 'I') { bool recordTemplateArgs = mIsFirstName && (mTemplateDepth == 0); if (recordTemplateArgs) mTemplateList.Clear(); mTemplateDepth++; bool inParamPack = false; bool foundEnd = false; bool needsComma = false; outName = "<"; for (int argIdx = 0; true; argIdx++) { if (mFailed) return true; if (DemangleEnd()) { if (inParamPack) { inParamPack = false; continue; } else break; } StringT<256> templateArg; auto firstChar = SafeGetChar(mMangledName, mCurIdx); if (firstChar == 'J') { mCurIdx++; inParamPack = true; continue; } Require(DemangleTemplateArg(templateArg)); if (recordTemplateArgs) mTemplateList.push_back(templateArg); if (needsComma) outName += ", "; outName += templateArg; needsComma = true; } outName += ">"; mTemplateDepth--; return true; } mCurIdx--; return false; } bool DwDemangler::DemangleSubstitution(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); if (firstChar == 'S') { int idx = 0; bool hadChars = 0; while (true) { char idxChar = SafeGetChar(mMangledName, mCurIdx++); if (idxChar == 't') { DemangleUnqualifiedName(outName); outName = "std." + outName; mSubstituteList.push_back(outName); mOmitSubstituteAdd = true; return true; } mOmitSubstituteAdd = true; if (idxChar == 'a') { RETURN_STR("std.allocator"); } if (idxChar == 'b') { RETURN_STR("std.basic_string"); } if (idxChar == 's') { RETURN_STR("std.string"); } if (idxChar == 'i') { RETURN_STR("std.basic_istream>"); } if (idxChar == 'o') { RETURN_STR("std.basic_ostream>"); } if (idxChar == 'd') { RETURN_STR("std.basic_iostream>"); } if (idxChar == '?') break; if (idxChar == '_') break; hadChars = true; if ((idxChar >= '0') && (idxChar <= '9')) idx = (idxChar - '0') + (idx * 36); else if ((idxChar >= 'A') && (idxChar <= 'Z')) idx = ((idxChar - 'A') + 10) + (idx * 36); } if (hadChars) idx++; if ((idx >= 0) && (idx < (int) mSubstituteList.size())) { outName = mSubstituteList[idx]; return true; } outName = "?"; Failed(); return true; } mCurIdx--; return false; } bool DwDemangler::DemangleTemplateParam(StringImpl& outName) { auto firstChar = SafeGetChar(mMangledName, mCurIdx++); if (firstChar == 'T') { int idx = 0; bool hadChars = 0; while (true) { char idxChar = SafeGetChar(mMangledName, mCurIdx++); if (idxChar == '?') break; if (idxChar == '_') break; hadChars = true; if ((idxChar >= '0') && (idxChar <= '9')) idx = (idxChar - '0') + (idx * 36); else if ((idxChar >= 'A') && (idxChar <= 'Z')) idx = ((idxChar - 'A') + 10) + (idx * 36); } if (hadChars) idx++; if ((idx >= 0) && (idx < (int)mTemplateList.size())) { outName = mTemplateList[idx]; mSubstituteList.push_back(outName); return true; } outName = "?"; Failed(); return true; } mCurIdx--; return false; } bool DwDemangler::DemangleUnscopedName(StringImpl& outName) { if (DemangleUnqualifiedName(outName)) return true; if (DemangleSubstitution(outName)) return true; return false; } bool DwDemangler::DemangleName(StringImpl& outName, bool* outHasTemplateArgs) { if (outHasTemplateArgs != NULL) *outHasTemplateArgs = false; auto firstChar = SafeGetChar(mMangledName, mCurIdx++); switch (firstChar) { case 'N': // NestedName { StringT<64> cvQualifier; if (DemangleCVQualifiers(cvQualifier)) outName += cvQualifier + " "; StringT<64> refQualifier; if (DemangleRefQualifier(refQualifier)) outName += refQualifier + " "; int nameCount = 0; while ((!DemangleEnd()) && (!mFailed)) { StringT<128> unqualifiedName; mOmitSubstituteAdd = false; if ((DemangleUnscopedName(unqualifiedName)) || (DemangleInternalName(unqualifiedName))) { if (outHasTemplateArgs != NULL) *outHasTemplateArgs = false; if (nameCount > 0) { if (mLanguage == DbgLanguage_Beef) outName += "."; else outName += "::"; } outName += unqualifiedName; if (!mOmitSubstituteAdd) mSubstituteList.push_back(outName); else mOmitSubstituteAdd = false; nameCount++; continue; } StringT<128> templateArgs; if (DemangleTemplateArgs(templateArgs)) { if (outHasTemplateArgs != NULL) *outHasTemplateArgs = true; int arrayDims = 0; if (!mRawDemangle) { if (outName == "__TUPLE") { outName = "(" + templateArgs.Substring(1, templateArgs.length() - 2) + ")"; mSubstituteList.push_back(outName); continue; } else if (outName == "Box") { outName = templateArgs.Substring(1, templateArgs.length() - 2) + "^"; mSubstituteList.push_back(outName); continue; } if (outName == "System.Array1") arrayDims = 1; else if (outName == "System.Array2") arrayDims = 2; else if (outName == "System.Array3") arrayDims = 3; } if (arrayDims > 0) { outName = templateArgs.Substring(1, templateArgs.length() - 2) + "["; for (int i = 0; i < arrayDims - 1; i++) outName += ","; outName += "]"; } else { outName += templateArgs; mSubstituteList.push_back(outName); } continue; } Failed(); break; } return true; } break; } mCurIdx--; if (DemangleUnscopedName(outName)) { if (!mOmitSubstituteAdd) mSubstituteList.push_back(outName); else mOmitSubstituteAdd = false; StringT<128> templateArgs; if (DemangleTemplateArgs(templateArgs)) { if (outHasTemplateArgs != NULL) *outHasTemplateArgs = true; outName += templateArgs; } if ((outName.length() > 0) && (outName[outName.length() - 1] == '.')) { // an incomplete 'std.' StringT<128> unqualifiedName; if ((DemangleUnscopedName(unqualifiedName)) || (DemangleInternalName(unqualifiedName))) { outName += unqualifiedName; } else { Failed(); } } return true; } if (DemangleLocalName(outName)) return true; return false; } String DwDemangler::Demangle(const StringImpl& mangledName) { BF_ASSERT(mCurIdx == 0); /*String overrideVal = "_ZZL9DumpStatsP16TCMalloc_PrinteriE3MiB"; //String overrideVal = "_ZN3Hey4Dude3Bro9TestClass7MethodBEivf"; //"_ZN3Hey4Dude3Bro9TestClass14DlgTestGenericIiE12TestThinggieEi"; //"_ZStL19piecewise_construct"; //"_ZNSbIwSt11char_traitsIwESaIwEED1Ev"; //"_ZN12_GLOBAL__N_124do_realloc_with_callbackEPvjPFvS0_EPFjPKvE"; //"_ZNK17TCMalloc_PageMap2ILi19EE3getEj"; //"_ZN5BeefyL13FromBigEndianEs"; //"_ZNSt6vectorIZN4BFGC19WriteDebugDumpStateEvE9DebugInfoSaIS1_EED2Ev"; //"_ZNSt6vectorISsSaISsEE19_M_emplace_back_auxIJRKSsEEEvDpOT_"; //"_ZSt4moveIRiEONSt16remove_referenceIT_E4typeEOS2_"; //"_ZL10CStartProcPN6System9Threading6ThreadE"; //"_ZNSt8_Rb_treeIPN6System9Threading6ThreadESt4pairIKS3_PS3_ESt10_Select1stIS7_ESt4lessIS3_ESaIS7_EE13_Rb_tree_implISB_Lb1EED2Ev"; //Clang failure: (?) "__ZNSt16allocator_traitsISaISsEE9constructISsJRKSsEEEDTcl12_S_constructfp_fp0_spclsr3stdE7forwardIT0_Efp1_EEERS0_PT_DpOS5_"; //"__ZNSt4pairIifEC2IKifvEERKS_IT_T0_E"; //"__ZNSsaSEPKc"; //"__ZN6System6String6ConcatEU6paramsPNS_6Array1INS_6ObjectEEE"; //_ZNSt3mapI3HeyfSt4lessIiESaISt4pairIKifEEEixES_S0_S1_S2_S3_S4_S5_S6_ String overrideDemangled; if (mangledName != overrideVal) { BfDemangler demangler; overrideDemangled = demangler.Demangle(overrideVal); }*/ mMangledName = mangledName; String outStr; if (mangledName.length() < 3) return mangledName; if (strncmp(mangledName.c_str(), "_Z", 2) == 0) mCurIdx = 2; else if (strncmp(mangledName.c_str(), "__Z", 3) == 0) mCurIdx = 3; else { int dotIdx = (int)mangledName.IndexOf('.'); if (dotIdx > 1) return mangledName.Substring(0, dotIdx) + ":" + Demangle(mangledName.Substring(dotIdx + 1)); return mangledName; } /*int ePos = (int) mMangledName.rfind('E'); if (ePos > 0) mMangledName = mMangledName.substr(0, mMangledName.length() - 1);*/ int endPos = (int)mMangledName.length() - 1; while (endPos > 0) { char c = mMangledName[endPos]; if (c == '@') { mMangledName = mMangledName.Substring(0, endPos); break; } bool isNum = (c >= '0') && (c <= '9'); if (!isNum) break; endPos--; } bool mayHaveParams = false; char typeChar = SafeGetChar(mangledName, mCurIdx); if (typeChar == 'T') { mCurIdx++; char typeChar2 = SafeGetChar(mangledName, mCurIdx++); if (typeChar2 == 'S') { // typeinfo } else if (typeChar2 == 'V') { // vtable } else { return mangledName; } } else if (typeChar == 'S') { mayHaveParams = false; } else if (typeChar == 'L') { mayHaveParams = true; mCurIdx++; } else if (typeChar == 'Z') // Static function-scoped field mayHaveParams = false; else mayHaveParams = true; bool wantsReturnValue = false; StringT<256> outName; if (mayHaveParams) Require(DemangleFunction(outName)); else Require(DemangleName(outName)); if (mFailed) return mangledName; //OutputDebugStrF("%s\n", outName.c_str()); return outName; } ////////////////////////////////////////////////////////////////////////// MsDemangler::MsDemangler() { mCurIdx = 0; } bool MsDemangler::DemangleString(StringImpl& outName) { while (true) { char c = SafeGetChar(mMangledName, mCurIdx++); if ((c == '!') || (c == '?')) return Failed(); if (c == '@') break; outName.Append(c); } //mSubstituteList.push_back(outName); return true; } bool MsDemangler::DemangleTemplateName(StringImpl& outName, String* primaryName) { DemangleString(outName); if (primaryName != NULL) *primaryName = outName; mSubstituteList.push_back(outName); outName += "<"; for (int paramIdx = 0; true; paramIdx++) { String paramType; if (!DemangleType(paramType)) break; if (paramIdx > 0) outName += ", "; outName += paramType; } outName += ">"; return true; } bool MsDemangler::DemangleScopedName(StringImpl& outName, String* primaryName) { for (int nameIdx = 0; true; nameIdx++) { if (mFailed) return false; char c = SafeGetChar(mMangledName, mCurIdx++); if (c == '@') return true; /*{ if (curScope.length() == 0) return true; if (nameIdx == 0) { if (primaryName != NULL) *primaryName = curScope; } else outName = "::" + outName; outName = curScope + outName; curScope.clear(); mSubstituteList.push_back(outName); nameIdx++; continue; }*/ String namePart; if (c == '?') { c = SafeGetChar(mMangledName, mCurIdx++); if (c == '$') { SubstituteList oldSubList = mSubstituteList; mSubstituteList.Clear(); DemangleTemplateName(namePart, /*primaryName*/NULL); mSubstituteList = oldSubList; } else if (c == '?') { return Failed(); } else { mCurIdx--; int num = DemangleNumber(); outName = StrFormat("%d", num); } } else if ((c >= '0') && (c <= '9')) { int subIdx = c - '0'; if (subIdx < mSubstituteList.size()) { namePart = mSubstituteList[subIdx]; } else { return Failed(); } } else { mCurIdx--; Require(DemangleString(namePart)); } if (nameIdx == 0) { //We moved this down so we get the template args for the ctor name /*if ((primaryName != NULL) && (primaryName->empty())) *primaryName = namePart;*/ outName = namePart; if ((primaryName != NULL) && (primaryName->empty())) *primaryName = namePart; } else if (mLanguage == DbgLanguage_Beef) { if ((mBeefFixed) && (namePart == "bf")) namePart.Clear(); if (!namePart.IsEmpty()) outName = namePart + "." + outName; } else { outName = namePart + "::" + outName; } mSubstituteList.push_back(namePart); } } bool MsDemangler::DemangleModifiedType(StringImpl& outName, bool isPtr) { String modifier; DemangleCV(modifier); char c = SafeGetChar(mMangledName, mCurIdx); if (c == 'Y') // Sized array { String dimStr; mCurIdx++; int dimCount = DemangleNumber(); for (int dim = 0; dim < dimCount; dim++) { int dimSize = DemangleNumber(); dimStr += StrFormat("[%d]", dimSize); } DemangleType(outName); outName += dimStr; } else { DemangleType(outName); if (isPtr) outName += "*"; } if (!modifier.empty()) outName = modifier + " " + outName; return true; } bool MsDemangler::DemangleType(StringImpl& outName) { char c = SafeGetChar(mMangledName, mCurIdx++); if ((c == 0) || (c == '@')) return false; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { if (mFailed) return false; int subIdx = c - '0'; if ((subIdx < 0) || (subIdx >= (int)mSubstituteList.size())) return Failed(); outName = mSubstituteList[subIdx]; return true; } break; case '$': { char c = SafeGetChar(mMangledName, mCurIdx++); switch (c) { case '0': { int64 val = 0; bool doNeg = false; auto nextChar = SafeGetChar(mMangledName, mCurIdx++); if (nextChar == '?') { doNeg = true; nextChar = SafeGetChar(mMangledName, mCurIdx++); } if ((nextChar >= '0') && (nextChar <= '9')) { val = (nextChar - '0') + 1; } else { while (true) { if (nextChar == 0) return Failed(); if (nextChar == '@') break; val = (val * 0x10) + (nextChar - 'A'); nextChar = SafeGetChar(mMangledName, mCurIdx++); } } if (doNeg) val = -val; if (mLanguage == DbgLanguage_Beef) outName += StrFormat("const %d", val); else outName += StrFormat("%d", val); return true; } break; case 'D': { int templateParamNum = DemangleNumber(); return Failed(); } break; case 'F': { int param1 = DemangleNumber(); int param2 = DemangleNumber(); return Failed(); } break; case 'G': { int param1 = DemangleNumber(); int param2 = DemangleNumber(); int param3 = DemangleNumber(); return Failed(); } break; case 'Q': { int nonTypeTemplateParam = DemangleNumber(); return Failed(); } break; case '$': { char c = SafeGetChar(mMangledName, mCurIdx++); if (c == 'C') { String modifier; DemangleCV(modifier); DemangleType(outName); outName = modifier + " " + outName; return true; } else if (c == 'Q') { String modifier; DemangleCV(modifier); DemangleType(outName); outName = modifier + " " + outName; return true; } } break; } } break; case '_': { c = SafeGetChar(mMangledName, mCurIdx++); switch (c) { case 'D': outName = "int8"; return true; case 'E': outName = "uint8"; return true; case 'F': outName = "int16"; return true; case 'G': outName = "uint16"; return true; case 'H': outName = "int32"; return true; case 'I': outName = "uint32"; return true; case 'J': outName = "int64"; return true; case 'K': outName = "uint64"; return true; case 'L': outName = "int128"; return true; case 'M': outName = "float"; return true; case 'W': outName = "wchar_t"; return true; case 'N': outName = "bool"; return true; default: return Failed(); break; } } break; case 'A': { DemangleModifiedType(outName, false); outName += "&"; } return true; case 'B': DemangleModifiedType(outName, false); outName = "volatile " + outName + "&"; return true; case 'P': DemangleModifiedType(outName, true); return true; case 'Q': DemangleModifiedType(outName, true); outName = "const " + outName; return true; case 'R': DemangleModifiedType(outName, true); outName = "volatile " + outName; return true; case 'S': DemangleModifiedType(outName, true); outName = "const volatile" + outName; return true; case 'T': // union DemangleScopedName(outName); return true; case 'U': // struct DemangleScopedName(outName); return true; case 'V': // class DemangleScopedName(outName); return true; case 'W': // enum c = SafeGetChar(mMangledName, mCurIdx++); Require((c >= '0') && (c <= '8')); DemangleScopedName(outName); return true; case 'C': outName = "char"; return true; case 'D': if (mLanguage == DbgLanguage_Beef) outName = "char8"; else outName = "char"; return true; case 'E': if (mLanguage == DbgLanguage_Beef) outName = "uint8"; else outName = "uchar"; return true; case 'F': if (mLanguage == DbgLanguage_Beef) outName = "int16"; else outName = "short"; return true; case 'G': if (mLanguage == DbgLanguage_Beef) outName = "uint16"; else outName = "ushort"; return true; case 'H': if (mLanguage == DbgLanguage_Beef) outName = "int32"; else outName = "int"; return true; case 'I': if (mLanguage == DbgLanguage_Beef) outName = "uint32"; else outName = "uint"; return true; case 'J': outName = "long"; return true; case 'K': outName = "ulong"; return true; case 'M': outName = "float"; return true; case 'N': outName = "double"; return true; case 'O': outName = "long double"; return true; case 'X': outName += "void"; return true; case '?': if (mInArgs) { int num = DemangleNumber(); // } else { DemangleModifiedType(outName, false); } break; default: return Failed(); break; } return false; } int MsDemangler::DemangleNumber() { char c = SafeGetChar(mMangledName, mCurIdx++); bool isSigned = false; if (c == '?') { isSigned = true; c = SafeGetChar(mMangledName, mCurIdx++); } if ((c >= '0') && (c <= '9')) { return c - '0' + 1; } int val = 0; while ((c >= 'A') && (c <= 'P')) { val = (val * 0x10) + (c - 'A'); c = SafeGetChar(mMangledName, mCurIdx++); } if (c != '@') Failed(); return val; } bool MsDemangler::DemangleCV(StringImpl& outName) { String modifier; while (true) { char c = SafeGetChar(mMangledName, mCurIdx++); if (c == 'E') { // __ptr64 } else if (c == 'F') { // Unaligned //BF_ASSERT("Unhandled"); } else if (c == 'I') { // __restrict } else break; } mCurIdx--; //int modifier = DemangleConst(); char c = SafeGetChar(mMangledName, mCurIdx++); int constVal = 0; //BF_ASSERT((c >= 'A') && (c <= 'X')); if ((c < 'A') || (c > 'X')) { return Failed(); } constVal = c - 'A'; if ((constVal & 3) == 3) outName = "const volatile"; else if ((constVal & 1) != 0) outName = "const"; else if ((constVal & 2) != 0) outName = "const"; /*switch (c) { case 'A': case 'M': case 'Q': case 'U': case 'Y': case '2': // None break; case 'B': case 'J': case 'R': case 'V': case 'Z': case '3': modifier = "const"; break; case 'C': case 'G': case 'K': case 'S': case 'W': case '0': modifier = "volatile"; break; case 'D': case 'H': case 'L': modifier = "const volatile"; break; default: BF_ASSERT("Unhandled"); }*/ return true; } bool MsDemangler::DemangleName(StringImpl& outName) { bool appendRetType = false; bool hasTemplateArgs = false; char c = SafeGetChar(mMangledName, mCurIdx++); if (c == '?') { c = SafeGetChar(mMangledName, mCurIdx++); if (c == '$') { mCurIdx++; c = SafeGetChar(mMangledName, mCurIdx++); hasTemplateArgs = true; } String primaryName; const char* funcName = NULL; switch (c) { case '0': // Ctor Require(DemangleScopedName(outName, &primaryName)); if (mLanguage == DbgLanguage_Beef) outName += ".this"; else outName += "::" + primaryName; break; case '1': // Dtor Require(DemangleScopedName(outName, &primaryName)); if (mLanguage == DbgLanguage_Beef) outName += ".~this"; else outName += "::~" + primaryName; break; case '2': funcName = "operator new"; break; case '3': funcName = "operator delete"; break; case '4': funcName = "operator="; break; case '5': funcName = "operator>>"; break; case '6': funcName = "operator<<"; break; case '7': funcName = "operator!"; break; case '8': funcName = "operator=="; break; case '9': funcName = "operator!="; break; case 'A': funcName = "operator[]"; break; case 'B': funcName = "operator "; appendRetType = true; break; case 'C': funcName = "operator->"; break; case 'D': funcName = "operator*"; break; case 'E': funcName = "operator++"; break; case 'F': funcName = "operator--"; break; case 'G': funcName = "operator-"; break; case 'H': funcName = "operator+"; break; case 'I': funcName = "operator&"; break; case 'J': funcName = "operator->*"; break; case 'K': funcName = "operator/"; break; case 'L': funcName = "operator%"; break; case 'M': funcName = "operator<"; break; case 'N': funcName = "operator<="; break; case 'O': funcName = "operator>"; break; case 'P': funcName = "operator>="; break; case 'Q': funcName = "operator,"; break; case 'R': funcName = "operator()"; break; case 'S': funcName = "operator~"; break; case 'T': funcName = "operator^"; break; case 'U': funcName = "operator|"; break; case 'V': funcName = "operator&&"; break; case 'W': funcName = "operator||"; break; case 'X': funcName = "operator*="; break; case 'Y': funcName = "operator+="; break; case 'Z': funcName = "operator-="; break; case '_': { c = SafeGetChar(mMangledName, mCurIdx++); switch (c) { case '0': funcName = "operator/="; break; case '1': funcName = "operator%="; break; case '2': funcName = "operator>>="; break; case '3': funcName = "operator<<="; break; case '4': funcName = "operator&="; break; case '5': funcName = "operator|="; break; case '6': funcName = "operator^="; break; case '7': funcName = "`vftable'"; break; case '8': funcName = "`vbtable'"; break; case '9': funcName = "`vcall'"; break; case 'A': funcName = "`typeof'"; break; case 'B': funcName = "`local static guard'"; break; //case 'C': funcName = "`string'"; do_after = 4; break; case 'D': funcName = "`vbase destructor'"; break; case 'E': funcName = "`vector deleting destructor'"; break; case 'F': funcName = "`default constructor closure'"; break; case 'G': funcName = "`scalar deleting destructor'"; break; case 'H': funcName = "`vector constructor iterator'"; break; case 'I': funcName = "`vector destructor iterator'"; break; case 'J': funcName = "`vector vbase constructor iterator'"; break; case 'K': funcName = "`virtual displacement map'"; break; case 'L': funcName = "`eh vector constructor iterator'"; break; case 'M': funcName = "`eh vector destructor iterator'"; break; case 'N': funcName = "`eh vector vbase constructor iterator'"; break; case 'O': funcName = "`copy constructor closure'"; break; case 'R': c = SafeGetChar(mMangledName, mCurIdx++); switch (c) { case 0: funcName = "`RTTI Type Descriptor'"; break; case 1: funcName = "`RTTI Class Descriptor'"; break; case '2': funcName = "`RTTI Base Class Array'"; break; case '3': funcName = "`RTTI Class Hierarchy Descriptor'"; break; case '4': funcName = "`RTTI Complete Object Locater"; break; } break; case 'S': funcName = "`local vftable'"; break; case 'T': funcName = "`local vftable constructor closure'"; break; case 'U': funcName = "operator new[]"; break; case 'V': funcName = "operator delete[]"; break; case 'X': funcName = "`placement delete closure'"; break; case 'Y': funcName = "`placement delete[] closure'"; break; } } break; default: mCurIdx -= 2; break; } if (funcName != NULL) { if (strcmp(funcName, "__BfCtor") == 0) funcName = "this"; else if (strcmp(funcName, "__BfCtorClear") == 0) funcName = "this$clear"; else if (strcmp(funcName, "__BfStaticCtor") == 0) funcName = "this"; if (hasTemplateArgs) { outName += funcName; outName += "<"; for (int paramIdx = 0; true; paramIdx++) { String paramType; if (!DemangleType(paramType)) break; if (paramType == "void") break; if (paramIdx > 0) outName += ", "; outName += paramType; } outName += ">"; mSubstituteList.Clear(); StringT<128> scopeName; Require(DemangleScopedName(scopeName, &primaryName)); if (!scopeName.empty()) { if (mLanguage == DbgLanguage_Beef) { scopeName += "."; } else scopeName += "::"; outName.Insert(0, scopeName); } /*outName += "("; for (int paramIdx = 0; true; paramIdx++) { String paramType; if (!DemangleType(paramType)) break; if (paramType == "void") break; if (paramIdx > 0) outName += ", "; outName += paramType; } outName += ")";*/ } else { Require(DemangleScopedName(outName, &primaryName)); if (!primaryName.empty()) { if (mLanguage == DbgLanguage_Beef) outName += "."; else outName += "::"; } outName += funcName; } } else if (outName.empty()) { if (hasTemplateArgs) { Require(DemangleString(outName)); primaryName = outName; outName += "<"; for (int paramIdx = 0; true; paramIdx++) { String paramType; if (!DemangleType(paramType)) break; if (paramType == "void") break; if (paramIdx > 0) outName += ", "; outName += paramType; } outName += ">"; mSubstituteList.Clear(); String scopeName; Require(DemangleScopedName(scopeName, &primaryName)); if (!scopeName.empty()) { if (mLanguage == DbgLanguage_Beef) scopeName += "."; else scopeName += "::"; outName.Insert(0, scopeName); } } else { Require(DemangleScopedName(outName, &primaryName)); } } } else { mCurIdx--; Require(DemangleScopedName(outName)); } c = SafeGetChar(mMangledName, mCurIdx++); if ((c >= '0') && (c <= '9')) { if ((c == '2') || (c == '3')) { // Global variable / static member String varType; Require(DemangleType(varType)); c = SafeGetChar(mMangledName, mCurIdx++); // 0 = private, 1 = protected, 2 = public return true; } return true; } // Method attribute if (c == 0) return true; struct { uint8 mUnused1 : 1; uint8 mType : 2; // normal, static, virtual, thunk uint8 mAccess : 3; // private, protected, public, non-member uint8 mUnused2 : 2; } methodData; *((uint8*)&methodData) = (c - 'A'); //int funcTypeVal = c - 'A'; //int accessType = funcTypeVal >> 3; //bool isNonMember = c == 'Y'; //bool isVirtual = (c == 'E') || (c == 'M') || (c == 'U'); //bool hasThis = isVirtual || (c == 'A') || (c == 'I') || (c == 'Q'); bool isNonMember = methodData.mAccess == 3; bool hasThis = !isNonMember && ((methodData.mType == 0) || (methodData.mType == 2)); // CV qualifier if (hasThis) { String cvQualifier; if (!DemangleCV(cvQualifier)) return false; // Ignore } // Calling convention c = SafeGetChar(mMangledName, mCurIdx++); union { uint8 mDllExport : 1; uint8 mCallingConv : 7; // cdecl, pascal, thiscall, stdcall, fastcall } callType; *((uint8*)&callType) = (c - 'A'); if (callType.mCallingConv > 6) return Failed(); String retType; DemangleType(retType); if (appendRetType) outName += retType; // This was needed for System.ValueType.Equals<_M0>(_M0, ValueType) // Do we need to clear ALWAYS before param list though? if (hasTemplateArgs) mSubstituteList.Clear(); mInArgs = true; outName += "("; for (int paramIdx = 0; true; paramIdx++) { String paramType; if (!DemangleType(paramType)) break; if (paramType == "void") break; if (paramIdx > 0) outName += ", "; outName += paramType; } outName += ")"; return true; } String MsDemangler::Demangle(const StringImpl& mangledName) { StringT<256> outName; mMangledName = mangledName; char c = mangledName[mCurIdx++]; BF_ASSERT(c == '?'); DemangleName(outName); if (mFailed) return mangledName; //return outName; //return outName + " : " + mangledName; return outName; } ////////////////////////////////////////////////////////////////////////// MsDemangleScanner::MsDemangleScanner() { mCurIdx = 0; mIsData = false; } bool MsDemangleScanner::DemangleString() { while (true) { char c = SafeGetChar(mMangledName, mCurIdx++); if ((c == '!') || (c == '?')) return Failed(); if (c == '@') break; } //mSubstituteList.push_back(outName); return true; } bool MsDemangleScanner::DemangleTemplateName() { DemangleString(); for (int paramIdx = 0; true; paramIdx++) { if (!DemangleType()) break; } return true; } bool MsDemangleScanner::DemangleScopedName() { for (int nameIdx = 0; true; nameIdx++) { if (mFailed) return false; char c = SafeGetChar(mMangledName, mCurIdx++); if (c == '@') return true; if (c == '?') { c = SafeGetChar(mMangledName, mCurIdx++); if (c == '$') { DemangleTemplateName(); } else if (c == '?') { return Failed(); } else { mCurIdx--; int num = DemangleNumber(); } } else if ((c >= '0') && (c <= '9')) { int subIdx = c - '0'; if (subIdx < mSubstituteList.size()) { // } else { return Failed(); } } else { mCurIdx--; Require(DemangleString()); } } } bool MsDemangleScanner::DemangleModifiedType(bool isPtr) { DemangleCV(); char c = SafeGetChar(mMangledName, mCurIdx); if (c == 'Y') // Sized array { mCurIdx++; int dimCount = DemangleNumber(); for (int dim = 0; dim < dimCount; dim++) { int dimSize = DemangleNumber(); } DemangleType(); } else { DemangleType(); } return true; } bool MsDemangleScanner::DemangleType() { char c = SafeGetChar(mMangledName, mCurIdx++); if ((c == 0) || (c == '@')) return false; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { if (mFailed) return false; int subIdx = c - '0'; if ((subIdx < 0) || (subIdx >= (int)mSubstituteList.size())) return Failed(); return true; } break; case '$': { char c = SafeGetChar(mMangledName, mCurIdx++); switch (c) { case '0': return Failed(); break; case 'D': { int templateParamNum = DemangleNumber(); return Failed(); } break; case 'F': { int param1 = DemangleNumber(); int param2 = DemangleNumber(); return Failed(); } break; case 'G': { int param1 = DemangleNumber(); int param2 = DemangleNumber(); int param3 = DemangleNumber(); return Failed(); } break; case 'Q': { int nonTypeTemplateParam = DemangleNumber(); return Failed(); } break; case '$': { char c = SafeGetChar(mMangledName, mCurIdx++); if (c == 'C') { DemangleCV(); DemangleType(); return true; } else if (c == 'Q') { DemangleCV(); DemangleType(); return true; } } break; } } break; case '_': { c = SafeGetChar(mMangledName, mCurIdx++); switch (c) { case 'D': return true; case 'E': return true; case 'F': return true; case 'G': return true; case 'H': return true; case 'I': return true; case 'J': return true; case 'K': return true; case 'L': return true; case 'M': return true; case 'W': return true; case 'N': return true; default: return Failed(); break; } } break; case 'A': { DemangleModifiedType(false); } return true; case 'B': DemangleModifiedType(false); return true; case 'P': DemangleModifiedType(true); return true; case 'Q': DemangleModifiedType(true); return true; case 'R': DemangleModifiedType(true); return true; case 'S': DemangleModifiedType(true); return true; case 'T': // union DemangleScopedName(); return true; case 'U': // struct DemangleScopedName(); return true; case 'V': // class DemangleScopedName(); return true; case 'W': // enum c = SafeGetChar(mMangledName, mCurIdx++); Require((c >= '0') && (c <= '8')); DemangleScopedName(); return true; case 'C': return true; case 'D': return true; case 'E': return true; case 'F': return true; case 'G': return true; case 'H': return true; case 'I': return true; case 'J': return true; case 'K': return true; case 'M': return true; case 'N': return true; case 'O': return true; case 'X': return true; case '?': if (mInArgs) { int num = DemangleNumber(); // } else { DemangleModifiedType(false); } break; default: return Failed(); break; } return false; } int MsDemangleScanner::DemangleNumber() { char c = SafeGetChar(mMangledName, mCurIdx++); bool isSigned = false; if (c == '?') { isSigned = true; c = SafeGetChar(mMangledName, mCurIdx++); } if ((c >= '0') && (c <= '9')) { return c - '0' + 1; } int val = 0; while ((c >= 'A') && (c <= 'P')) { val = (val * 10) + (c - 'A'); c = SafeGetChar(mMangledName, mCurIdx++); } if (c != '@') Failed(); return val; } bool MsDemangleScanner::DemangleCV() { while (true) { char c = SafeGetChar(mMangledName, mCurIdx++); if (c == 'E') { // __ptr64 } else if (c == 'F') { // Unaligned //BF_ASSERT("Unhandled"); } else if (c == 'I') { // __restrict } else break; } mCurIdx--; char c = SafeGetChar(mMangledName, mCurIdx++); int constVal = 0; if ((c < 'A') || (c > 'X')) { return Failed(); } constVal = c - 'A'; return true; } bool MsDemangleScanner::DemangleName() { bool appendRetType = false; bool hasTemplateArgs = false; char c = SafeGetChar(mMangledName, mCurIdx++); if (c == '?') { // A ?? is always a function return true; } else { mCurIdx--; Require(DemangleScopedName()); } c = SafeGetChar(mMangledName, mCurIdx++); if ((c >= '0') && (c <= '9')) { // Global variable / static member mIsData = true; return true; } // Not data return true; } void MsDemangleScanner::Process(const StringImpl& mangledName) { mMangledName = mangledName; char c = mangledName[mCurIdx++]; BF_ASSERT(c == '?'); DemangleName(); if (mFailed) { mIsData = false; } } ////////////////////////////////////////////////////////////////////////// String BfDemangler::Demangle(const StringImpl& mangledName, DbgLanguage language, Flags flags) { if (mangledName.IsEmpty()) return ""; if (mangledName[0] == '?') { MsDemangler demangler; demangler.mLanguage = language; demangler.mBeefFixed = (flags & BfDemangler::Flag_BeefFixed) != 0; return demangler.Demangle(mangledName); } else { DwDemangler demangler; demangler.mLanguage = language; demangler.mCaptureTargetType = (flags & BfDemangler::Flag_CaptureTargetType) != 0; demangler.mRawDemangle = (flags & BfDemangler::Flag_RawDemangle) != 0; demangler.mBeefFixed = (flags & BfDemangler::Flag_BeefFixed) != 0; return demangler.Demangle(mangledName); } } bool BfDemangler::IsData(const StringImpl& mangledName) { if (mangledName[0] == '?') { MsDemangleScanner demangler; demangler.Process(mangledName); return demangler.mIsData; } return false; }