123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- #include "DebugVisualizers.h"
- USING_NS_BF;
- void DebugVisualizers::Fail(const StringImpl& error)
- {
- if (mErrorString.length() != 0)
- return;
- mErrorString = StrFormat("Debug visualizer failure: %s in %s", error.c_str(), mCurFileName.c_str());
- }
- void DebugVisualizers::Fail(const StringImpl& error, const toml::Value& value)
- {
- if (mErrorString.length() != 0)
- return;
- if (value.lineNo != -1)
- mErrorString = StrFormat("Debug visualizer failure: %s at line %d in %s", error.c_str(), value.lineNo, mCurFileName.c_str());
- else
- mErrorString = StrFormat("Debug visualizer failure: %s in %s", error.c_str(), mCurFileName.c_str());
- }
- DebugVisualizers::DebugVisualizers()
- {
- mSrcStr = NULL;
- }
- static bool StrEquals(const char* str1, const char* str2)
- {
- if (str1 == str2)
- return true;
- if ((str1 == NULL) || (str2 == NULL))
- return false;
- return strcmp(str1, str2) == 0;
- }
- bool DebugVisualizers::ExpectBool(const toml::Value& value)
- {
- if (!value.is<bool>())
- {
- Fail("Expected boolean", value);
- return false;
- }
- const auto& val = value.as<bool>();
- return val;
- }
- String DebugVisualizers::ExpectString(const toml::Value& value)
- {
- if (!value.is<std::string>())
- {
- Fail("Expected string", value);
- return "";
- }
- const auto& val = value.as<std::string>();
- return val;
- }
- const toml::Table& DebugVisualizers::ExpectTable(const toml::Value& value)
- {
- static toml::Table emptyTable;
- if (!value.is<toml::Table>())
- {
- Fail("Expected table", value);
- return emptyTable;
- }
- return value.as<toml::Table>();
- }
- const toml::Array& DebugVisualizers::ExpectArray(const toml::Value& value)
- {
- static toml::Array emptyArray;
- if (!value.is<toml::Array>())
- {
- Fail("Expected array", value);
- return emptyArray;
- }
- return value.as<toml::Array>();
- }
- bool DebugVisualizers::ReadFileTOML(const StringImpl& fileName)
- {
- std::ifstream ifs(fileName);
- toml::ParseResult pr = toml::parse(ifs);
- if (!pr.valid())
- {
- Fail(pr.errorReason);
- return false;
- }
- const toml::Table& root = pr.value.as<toml::Table>();
- for (auto& kv : root)
- {
- auto& topName = kv.first;
- auto& topValue = kv.second;
- if (topName == "Type")
- {
- for (auto typeValue : ExpectArray(topValue))
- {
- auto& value = kv.second;
- DebugVisualizerEntry* entry = mDebugVisualizers.Alloc();
- for (auto& kv : ExpectTable(typeValue))
- {
- auto& name = kv.first;
- auto& value = kv.second;
- if (name == "Name")
- {
- entry->mName = ExpectString(value);
- }
- else if (name == "Flavor")
- {
- String flavorName = ExpectString(value);
- if (flavorName == "GNU")
- entry->mFlavor = DbgFlavor_GNU;
- else if (flavorName == "MS")
- entry->mFlavor = DbgFlavor_MS;
- else
- Fail("Unexpected flavor", value);
- }
- else if ((name == "DisplayString") | (name == "StringView"))
- {
- bool isStringView = name == "StringView";
-
- if (value.is<toml::Array>())
- {
- for (auto& displayValue : ExpectArray(value))
- {
- DebugVisualizerEntry::DisplayStringEntry* displayStringEntry = new DebugVisualizerEntry::DisplayStringEntry();
- for (auto& kv : ExpectTable(displayValue))
- {
- auto& name = kv.first;
- auto& value = kv.second;
- if (name == "Condition")
- displayStringEntry->mCondition = ExpectString(value);
- else if (name == "String")
- displayStringEntry->mString = ExpectString(value);
- else
- Fail("Unexpected entry", value);
- }
-
- if (isStringView)
- entry->mStringViews.push_back(displayStringEntry);
- else
- entry->mDisplayStrings.push_back(displayStringEntry);
- }
- }
- else
- {
- DebugVisualizerEntry::DisplayStringEntry* displayStringEntry = new DebugVisualizerEntry::DisplayStringEntry();
- displayStringEntry->mString = ExpectString(value);
- if (isStringView)
- entry->mStringViews.push_back(displayStringEntry);
- else
- entry->mDisplayStrings.push_back(displayStringEntry);
- }
- }
- else if (name == "Action")
- {
- entry->mAction = ExpectString(value);
- }
- else if (name == "Expand")
- {
- for (auto& kv : ExpectTable(value))
- {
- auto& name = kv.first;
- auto& value = kv.second;
- if (name == "ExpandedItem")
- {
- entry->mCollectionType = DebugVisualizerEntry::CollectionType_ExpandedItem;
- entry->mValuePointer = ExpectString(value);
- }
- else if (name == "Item")
- {
- for (auto& itemValue : ExpectArray(value))
- {
- DebugVisualizerEntry::ExpandItem* expandItem = entry->mExpandItems.Alloc();
- for (auto& kv : ExpectTable(itemValue))
- {
- auto& name = kv.first;
- auto& value = kv.second;
- if (name == "Name")
- expandItem->mName = ExpectString(value);
- else if (name == "Value")
- expandItem->mValue = ExpectString(value);
- else if (name == "Condition")
- expandItem->mCondition = ExpectString(value);
- else
- Fail("Unexpected entry", value);
- }
- }
- }
- else if (name == "ArrayItems")
- {
- entry->mCollectionType = DebugVisualizerEntry::CollectionType_Array;
- for (auto& kv : ExpectTable(value))
- {
- auto& name = kv.first;
- auto& value = kv.second;
- if (name == "Size")
- entry->mSize = ExpectString(value);
- else if (name == "LowerDimSizes")
- {
- for (auto& dimValue : ExpectArray(value))
- entry->mLowerDimSizes.push_back(ExpectString(dimValue));
- }
- else if (name == "ValuePointer")
- entry->mValuePointer = ExpectString(value);
- else if (name == "Condition")
- entry->mCondition = ExpectString(value);
- else
- Fail("Unexpected entry", value);
- }
- }
- else if (name == "IndexListItems")
- {
- entry->mCollectionType = DebugVisualizerEntry::CollectionType_IndexItems;
- for (auto& kv : ExpectTable(value))
- {
- auto& name = kv.first;
- auto& value = kv.second;
- if (name == "Size")
- entry->mSize = ExpectString(value);
- else if (name == "LowerDimSizes")
- {
- for (auto& dimValue : ExpectArray(value))
- entry->mLowerDimSizes.push_back(ExpectString(dimValue));
- }
- else if (name == "ValueNode")
- entry->mValuePointer = ExpectString(value);
- else
- Fail("Unexpected entry", value);
- }
- }
- else if (name == "TreeItems")
- {
- entry->mCollectionType = DebugVisualizerEntry::CollectionType_TreeItems;
- for (auto& kv : ExpectTable(value))
- {
- auto& name = kv.first;
- auto& value = kv.second;
- if (name == "Size")
- entry->mSize = ExpectString(value);
- else if (name == "HeadPointer")
- entry->mHeadPointer = ExpectString(value);
- else if (name == "LeftPointer")
- entry->mLeftPointer = ExpectString(value);
- else if (name == "RightPointer")
- entry->mRightPointer = ExpectString(value);
- else if (name == "ValuePointer")
- entry->mValuePointer = ExpectString(value);
- else if (name == "ValueType")
- entry->mValueType = ExpectString(value);
- else if (name == "Condition")
- entry->mCondition = ExpectString(value);
- else
- Fail("Unexpected entry", value);
- }
- }
- else if (name == "LinkedListItems")
- {
- entry->mCollectionType = DebugVisualizerEntry::CollectionType_LinkedList;
- for (auto& kv : ExpectTable(value))
- {
- auto& name = kv.first;
- auto& value = kv.second;
- if (name == "HeadPointer")
- entry->mHeadPointer = ExpectString(value);
- else if (name == "Size")
- entry->mSize = ExpectString(value);
- else if (name == "EndPointer")
- entry->mEndPointer = ExpectString(value);
- else if (name == "NextPointer")
- entry->mNextPointer = ExpectString(value);
- else if (name == "ValuePointer")
- entry->mValuePointer = ExpectString(value);
- else if (name == "ValueType")
- entry->mValueType = ExpectString(value);
- else if (name == "DynValueType")
- entry->mDynValueType = ExpectString(value);
- else if (name == "DynValueTypeIdAppend")
- entry->mDynValueTypeIdAppend = ExpectString(value);
- else if (name == "ShowElementAddrs")
- entry->mShowElementAddrs = ExpectBool(value);
- else
- Fail("Unexpected entry", value);
- }
- }
- else if (name == "DictionaryItems")
- {
- entry->mCollectionType = DebugVisualizerEntry::CollectionType_Dictionary;
- for (auto& kv : ExpectTable(value))
- {
- auto& name = kv.first;
- auto& value = kv.second;
- if (name == "Size")
- entry->mSize = ExpectString(value);
- else if (name == "Buckets")
- entry->mBuckets = ExpectString(value);
- else if (name == "Entries")
- entry->mEntries = ExpectString(value);
- else if (name == "Key")
- entry->mKey = ExpectString(value);
- else if (name == "Value")
- entry->mValuePointer = ExpectString(value);
- else if (name == "Next")
- entry->mNextPointer = ExpectString(value);
- else
- Fail("Unexpected entry", value);
- }
- }
- else
- Fail("Unexpected entry", value);
- }
- }
- else
- Fail("Unexpected entry", value);
- }
- }
- }
- else
- Fail(StrFormat("Unexpected key '%s'", topName.c_str()), topValue);
- }
- return mErrorString.IsEmpty();
- }
- bool DebugVisualizers::Load(const StringImpl& fileNamesStr)
- {
- bool hasError = !mErrorString.IsEmpty();
- mErrorString.Clear();
- Array<String> fileNames;
- int startIdx = 0;
- while (true)
- {
- int crPos = (int)fileNamesStr.IndexOf('\n', startIdx);
- if (crPos == -1)
- {
- fileNames.Add(fileNamesStr.Substring(startIdx));
- break;
- }
- fileNames.Add(fileNamesStr.Substring(startIdx, crPos - startIdx));
- startIdx = crPos + 1;
- }
-
- HashContext hashCtx;
- for (auto fileName : fileNames)
- {
- hashCtx.MixinStr(fileName);
- BfpTimeStamp lastWrite = BfpFile_GetTime_LastWrite(fileName.c_str());
- if (lastWrite == 0)
- {
- Fail(StrFormat("Failed to load debug visualizer file %s", fileName.c_str()));
- }
- hashCtx.Mixin(lastWrite);
- }
-
- Val128 hash = hashCtx.Finish128();
- if ((hash == mHash) && (!hasError))
- return true;
- mHash = hash;
- mDebugVisualizers.Clear();
- bool success = true;
- for (auto fileName : fileNames)
- {
- mCurFileName = fileName;
- if (!ReadFileTOML(fileName))
- success = false;
- mCurFileName.Clear();
- }
- return success;
- }
- DebugVisualizerEntry* DebugVisualizers::FindEntryForType(const StringImpl& typeName, DbgFlavor wantFlavor, Array<String>* wildcardCaptures)
- {
- //TODO: Do smarter name matching. Right now we just compare up to the '*'
-
- for (auto entry : mDebugVisualizers)
- {
- if ((entry->mFlavor != DbgFlavor_Unknown) && (entry->mFlavor != wantFlavor))
- continue;
- const char* entryCharP = entry->mName.c_str();
- const char* typeCharP = typeName.c_str();
- bool isTemplate = false;
- while (true)
- {
- while (*typeCharP == ' ')
- typeCharP++;
- while (*entryCharP == ' ')
- entryCharP++;
- char typeC = *typeCharP;
- char entryC = *entryCharP;
- if (typeC == 0)
- {
- if (entryC == 0)
- return entry;
- break;
- }
- else if (entryC == 0)
- break;
- if (entryC == '<')
- isTemplate = true;
- if (entryC == '*')
- {
- int openDepth = 0;
- String wildcardCapture;
- while (true)
- {
- typeC = *typeCharP;
- bool isSep = typeC == ',';
- if ((!isTemplate) && ((typeC == '[') || (typeC == '?')))
- isSep = true;
- if (typeC == 0)
- break;
- if ((typeC == '<') || (typeC == '('))
- openDepth++;
- else if ((typeC == '>') || (typeC == ')'))
- {
- openDepth--;
- if (openDepth < 0)
- {
- typeCharP--;
- break;
- }
- }
- else if ((isSep) && (openDepth == 0))
- {
- typeCharP--;
- break;
- }
- wildcardCapture += typeC;
- typeCharP++;
- }
- if ((*typeCharP == 0) && (entryCharP[1] == 0))
- return entry;
- if (*typeCharP == 0)
- break;
- if (wildcardCaptures != NULL)
- wildcardCaptures->push_back(Trim(wildcardCapture));
- }
- else if (entryC != typeC)
- break;
-
- typeCharP++;
- entryCharP++;
- }
- if (wildcardCaptures != NULL)
- wildcardCaptures->Clear();
- }
- return NULL;
- }
- String DebugVisualizers::DoStringReplace(const StringImpl& origStr, const Array<String>& wildcardCaptures)
- {
- String newString = origStr;
- for (int i = 0; i < (int)newString.length(); i++)
- {
- if ((newString[i] == '$') && (newString[i + 1] == 'T'))
- {
- int wildcardIdx = (int)newString[i + 2] - '1';
- if ((wildcardIdx >= 0) && (wildcardIdx < (int)wildcardCaptures.size()))
- {
- newString = newString.Substring(0, i) + wildcardCaptures[wildcardIdx] + newString.Substring(i + 3);
- i += 2;
- }
- }
- }
- return newString;
- }
|