From 596922bb7f69c3f2c267415886e90574efc53d59 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Mon, 17 Dec 2012 20:46:27 -0500 Subject: [PATCH] Add CLI print variable command. --- src/apps/debugger/Jamfile | 3 +- .../cli/CliPrintVariableCommand.cpp | 172 ++++++++++++++++++ .../cli/CliPrintVariableCommand.h | 33 ++++ .../cli/CommandLineUserInterface.cpp | 2 + 4 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 src/apps/debugger/user_interface/cli/CliPrintVariableCommand.cpp create mode 100644 src/apps/debugger/user_interface/cli/CliPrintVariableCommand.h diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 4a3795c974..0d7ea52b64 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -193,12 +193,13 @@ Application Debugger : CliContext.cpp CliContinueCommand.cpp CliDebugReportCommand.cpp + CliPrintVariableCommand.cpp + CliQuitCommand.cpp CliStackFrameCommand.cpp CliStackTraceCommand.cpp CliStopCommand.cpp CliThreadCommand.cpp CliThreadsCommand.cpp - CliQuitCommand.cpp CliVariablesCommand.cpp CommandLineUserInterface.cpp diff --git a/src/apps/debugger/user_interface/cli/CliPrintVariableCommand.cpp b/src/apps/debugger/user_interface/cli/CliPrintVariableCommand.cpp new file mode 100644 index 0000000000..335dba6f76 --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliPrintVariableCommand.cpp @@ -0,0 +1,172 @@ +/* + * Copyright 2012, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ + + +#include "CliPrintVariableCommand.h" + +#include + +#include + +#include "CliContext.h" +#include "StackFrame.h" +#include "StackTrace.h" +#include "Team.h" +#include "Type.h" +#include "UiUtils.h" +#include "UserInterface.h" +#include "ValueLoader.h" +#include "ValueLocation.h" +#include "ValueNode.h" +#include "ValueNodeContainer.h" +#include "ValueNodeManager.h" + + +CliPrintVariableCommand::CliPrintVariableCommand() + : + CliCommand("print value(s) of a variable", + "%s [--depth n] variable [variable2 ...]\n" + "Prints the value and members of the named variable.") +{ +} + + +void +CliPrintVariableCommand::Execute(int argc, const char* const* argv, + CliContext& context) +{ + if (argc < 2) { + PrintUsage(argv[0]); + return; + } + + ValueNodeManager* manager = context.GetValueNodeManager(); + + ValueNodeContainer* container = manager->GetContainer(); + AutoLocker containerLocker(container); + if (container == NULL || container->CountChildren() == 0) { + printf("No variables available.\n"); + return; + } + + int32 depth = 1; + int32 i = 1; + for (; i < argc; i++) { + if (strcmp(argv[i], "--depth") == 0) { + if (i == argc - 1) { + printf("Error: An argument must be supplied for depth.\n"); + return; + } + char* endPointer; + depth = strtol(argv[i + 1], &endPointer, 0); + if (*endPointer != '\0' || depth < 0) { + printf("Error: Invalid parameter \"%s\"\n", argv[i + 1]); + return; + } + i++; + } + else + break; + } + + if (i == argc) { + printf("Error: At least one variable name must be supplied.\n"); + return; + } + + bool found = false; + while (i < argc) { + // TODO: support variable expressions in addition to just names. + const char* variableName = argv[i++]; + for (int32 j = 0; ValueNodeChild* child = container->ChildAt(j); j++) { + if (child->Name() == variableName) { + found = true; + containerLocker.Unlock(); + _ResolveValueIfNeeded(child->Node(), context, depth); + containerLocker.Lock(); + BString data; + UiUtils::PrintValueNodeGraph(data, child, 1, depth); + printf("%s", data.String()); + } + } + + if (!found) + printf("No such variable: %s\n", variableName); + found = false; + } +} + + +status_t +CliPrintVariableCommand::_ResolveValueIfNeeded(ValueNode* node, + CliContext& context, int32 maxDepth) +{ + StackFrame* frame = context.GetStackTrace()->FrameAt( + context.CurrentStackFrameIndex()); + if (frame == NULL) + return B_BAD_DATA; + + status_t result = B_OK; + ValueNodeManager* manager = context.GetValueNodeManager(); + ValueNodeContainer* container = manager->GetContainer(); + AutoLocker containerLocker(container); + if (node->LocationAndValueResolutionState() == VALUE_NODE_UNRESOLVED) { + context.GetUserInterfaceListener()->ValueNodeValueRequested( + context.CurrentThread()->GetCpuState(), container, node); + + // TODO: implement proper waiting + while (!context.IsTerminating()) { + context.ProcessPendingEvents(); + if (node->LocationAndValueResolutionState() + != VALUE_NODE_UNRESOLVED) { + break; + } + containerLocker.Unlock(); + snooze(20000); + containerLocker.Lock(); + } + } + + if (node->LocationAndValueResolutionState() == B_OK && maxDepth > 0) { + for (int32 i = 0; i < node->CountChildren(); i++) { + ValueNodeChild* child = node->ChildAt(i); + containerLocker.Unlock(); + result = _ResolveLocationIfNeeded(child, frame, context.GetTeam()); + if (result != B_OK) + continue; + + result = manager->AddChildNodes(child); + if (result != B_OK) + continue; + + // since in the case of a pointer to a compound we hide + // the intervening compound, don't consider the hidden node + // a level for the purposes of depth traversal + if (node->GetType()->Kind() == TYPE_ADDRESS + && child->GetType()->Kind() == TYPE_COMPOUND) { + _ResolveValueIfNeeded(child->Node(), context, maxDepth); + } else + _ResolveValueIfNeeded(child->Node(), context, maxDepth - 1); + containerLocker.Lock(); + } + } + + return result; +} + + +status_t +CliPrintVariableCommand::_ResolveLocationIfNeeded(ValueNodeChild* child, + StackFrame* frame, ::Team* team) +{ + ValueLocation* location = NULL; + ValueLoader loader(team->GetArchitecture(), team->GetTeamMemory(), + team->GetTeamTypeInformation(), frame->GetCpuState()); + status_t result = child->ResolveLocation(&loader, location); + child->SetLocation(location, result); + if (location != NULL) + location->ReleaseReference(); + return result; +} diff --git a/src/apps/debugger/user_interface/cli/CliPrintVariableCommand.h b/src/apps/debugger/user_interface/cli/CliPrintVariableCommand.h new file mode 100644 index 0000000000..aae38adcfc --- /dev/null +++ b/src/apps/debugger/user_interface/cli/CliPrintVariableCommand.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012, Rene Gollent, rene@gollent.com. + * Distributed under the terms of the MIT License. + */ +#ifndef CLI_PRINT_VARIABLE_COMMAND_H +#define CLI_PRINT_VARIABLE_COMMAND_H + + +#include "CliCommand.h" + + +class Team; +class StackFrame; +class ValueNode; +class ValueNodeChild; + + +class CliPrintVariableCommand : public CliCommand { +public: + CliPrintVariableCommand(); + virtual void Execute(int argc, const char* const* argv, + CliContext& context); + +private: + status_t _ResolveValueIfNeeded(ValueNode* node, + CliContext& context, int32 maxDepth); + + status_t _ResolveLocationIfNeeded(ValueNodeChild* child, + StackFrame* frame, ::Team* team); +}; + + +#endif // CLI_PRINT_VARIABLE_COMMAND_H diff --git a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp index de846471e2..92ef51139c 100644 --- a/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp +++ b/src/apps/debugger/user_interface/cli/CommandLineUserInterface.cpp @@ -18,6 +18,7 @@ #include "CliContext.h" #include "CliContinueCommand.h" #include "CliDebugReportCommand.h" +#include "CliPrintVariableCommand.h" #include "CliQuitCommand.h" #include "CliStackFrameCommand.h" #include "CliStackTraceCommand.h" @@ -313,6 +314,7 @@ CommandLineUserInterface::_RegisterCommands() && _RegisterCommand("continue", new(std::nothrow) CliContinueCommand) && _RegisterCommand("frame", new(std::nothrow) CliStackFrameCommand) && _RegisterCommand("help", new(std::nothrow) HelpCommand(this)) + && _RegisterCommand("print", new(std::nothrow) CliPrintVariableCommand) && _RegisterCommand("quit", new(std::nothrow) CliQuitCommand) && _RegisterCommand("save-report", new(std::nothrow) CliDebugReportCommand)