From 39ab14bc596dcd98842a804745cfd4156c6b3b7a Mon Sep 17 00:00:00 2001 From: Igor Kulaychuk Date: Mon, 10 Jul 2017 22:22:22 +0300 Subject: [PATCH] Add var-create, var-list-children and var-delete commands --- src/debug/debugger/main.cpp | 74 ++++++++++++++++++++++++++++++++++- src/debug/debugger/varobj.cpp | 91 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 151 insertions(+), 14 deletions(-) diff --git a/src/debug/debugger/main.cpp b/src/debug/debugger/main.cpp index ce8d755..da32f5e 100644 --- a/src/debug/debugger/main.cpp +++ b/src/debug/debugger/main.cpp @@ -128,7 +128,9 @@ void NotifyEvalComplete(); // Varobj HRESULT ListVariables(ICorDebugFrame *pFrame, std::string &output); - +HRESULT CreateVar(ICorDebugFrame *pFrame, const std::string &varobjName, const std::string &expression, std::string &output); +HRESULT ListChildren(const std::string &name, ICorDebugFrame *pFrame, std::string &output); +HRESULT DeleteVar(const std::string &varobjName); // TypePrinter #include "typeprinter.h" @@ -1166,6 +1168,76 @@ int main(int argc, char *argv[]) out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr); } } + else if (command == "var-create") + { + if (args.size() < 2) + { + out_printf("%s^error,msg=\"%s requires at least 2 arguments\"\n", token.c_str(), command.c_str()); + } else { + // TODO: Add parsing arguments --thread, --frame + std::string output; + HRESULT hr; + { + std::lock_guard lock(g_currentThreadMutex); + + ToRelease pFrame; + hr = g_currentThread ? g_currentThread->GetActiveFrame(&pFrame) : E_FAIL; + if (SUCCEEDED(hr)) + hr = CreateVar(pFrame, args.at(0), args.at(1), output); + } + if (SUCCEEDED(hr)) + { + out_printf("%s^done,%s\n", token.c_str(), output.c_str()); + } + else + { + out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr); + } + } + } + else if (command == "var-list-children") + { + if (args.size() < 1) + { + out_printf("%s^error,msg=\"%s requires an argument\"\n", token.c_str(), command.c_str()); + } else { + // TODO: Add parsing arguments --thread, --frame + std::string output; + HRESULT hr; + { + std::lock_guard lock(g_currentThreadMutex); + + ToRelease pFrame; + hr = g_currentThread ? g_currentThread->GetActiveFrame(&pFrame) : E_FAIL; + if (SUCCEEDED(hr)) + hr = ListChildren(args.at(0), pFrame, output); + } + if (SUCCEEDED(hr)) + { + out_printf("%s^done,%s\n", token.c_str(), output.c_str()); + } + else + { + out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr); + } + } + } + else if (command == "var-delete") + { + if (args.size() < 1) + { + out_printf("%s^error,msg=\"%s requires at least 1 argument\"\n", token.c_str(), command.c_str()); + } else { + if (SUCCEEDED(DeleteVar(args.at(0)))) + { + out_printf("%s^done\n", token.c_str()); + } + else + { + out_printf("%s^error,msg=\"Varible %s does not exits\"\n", token.c_str(), args.at(0).c_str()); + } + } + } else if (command == "gdb-exit") { hr = pProcess->Stop(0); diff --git a/src/debug/debugger/varobj.cpp b/src/debug/debugger/varobj.cpp index 0bcb83d..0a2884e 100644 --- a/src/debug/debugger/varobj.cpp +++ b/src/debug/debugger/varobj.cpp @@ -190,6 +190,29 @@ void PrintChildren(std::vector &members, std::string &output) output = ss.str(); } +static unsigned int g_varCounter = 0; +static std::unordered_map g_vars; + +static std::string InsertVar(VarObjValue &varobj) +{ + std::string varName = varobj.varobjName; + + if (varName.empty() || varName == "-") + { + varName = "var" + std::to_string(g_varCounter++); + } + + varobj.varobjName = varName; + + auto it = g_vars.find(varName); + if (it != g_vars.end()) + g_vars.erase(it); + + g_vars.emplace(std::make_pair(varName, varobj)); + + return varName; +} + HRESULT ListChildren(VarObjValue &objValue, ICorDebugFrame *pFrame, std::string &output) { HRESULT Status; @@ -226,23 +249,21 @@ HRESULT ListChildren(VarObjValue &objValue, ICorDebugFrame *pFrame, std::string Status = GetNumChild(m.value, m.numchild, m.statics_only); if (!m.statics_only) TypePrinter::GetTypeOfValue(m.value, m.typeName); + + InsertVar(m); } PrintChildren(members, output); - for (auto m : members) - { - if (m.value) - m.value->Release(); - } - return S_OK; } -HRESULT ListChildren(ICorDebugValue *pInputValue, ICorDebugFrame *pFrame, std::string &output) +HRESULT ListChildren(const std::string &name, ICorDebugFrame *pFrame, std::string &output) { - VarObjValue val("?", pInputValue, ""); - return ListChildren(val, pFrame, output); + auto it = g_vars.find(name); + if (it == g_vars.end()) + return E_FAIL; + return ListChildren(it->second, pFrame, output); } HRESULT ListVariables(ICorDebugFrame *pFrame, std::string &output) @@ -272,10 +293,6 @@ HRESULT ListVariables(ICorDebugFrame *pFrame, std::string &output) ss << ",type=\"" << strVal << "\""; } - std::string test; - ListChildren(pValue, pFrame, test); - ss << test; - ss << "}"; sep = ","; return S_OK; @@ -285,3 +302,51 @@ HRESULT ListVariables(ICorDebugFrame *pFrame, std::string &output) output = ss.str(); return S_OK; } + +HRESULT CreateVar(ICorDebugFrame *pFrame, const std::string &varobjName, const std::string &expression, std::string &output) +{ + HRESULT Status; + + ToRelease pILFrame; + IfFailRet(pFrame->QueryInterface(IID_ICorDebugILFrame, (LPVOID*) &pILFrame)); + + ICorDebugValue *pResultValue = nullptr; + IfFailRet(WalkStackVars(pFrame, [&](ICorDebugILFrame *pILFrame, ICorDebugValue *pValue, const std::string &name) -> HRESULT + { + if (pResultValue) + return S_OK; // TODO: Create a fast way to exit + + if (name == expression && pValue) + { + pValue->AddRef(); + pResultValue = pValue; + } + return S_OK; + })); + + if (!pResultValue) + return E_FAIL; + + VarObjValue varobj(expression, pResultValue, ""); + varobj.varobjName = varobjName; + GetNumChild(varobj.value, varobj.numchild, varobj.statics_only); + TypePrinter::GetTypeOfValue(varobj.value, varobj.typeName); + + std::string valName = InsertVar(varobj); + + std::string valStr; + PrintValue(varobj.value, pILFrame, valStr); + + std::stringstream ss; + ss << "name=\"" << valName << "\",numchild=\"" << varobj.numchild << "\",value=\"" << valStr + <<"\",type=\"" << varobj.typeName << "\""; + //name="var0",numchild="7",value="{Class2}",attributes="editable",type="Class2",thread-id="3945",has_more="1" + output = ss.str(); + + return S_OK; +} + +HRESULT DeleteVar(const std::string &varobjName) +{ + return g_vars.erase(varobjName) == 0 ? E_FAIL : S_OK; +} -- 2.7.4