Add CLI print variable command.

This commit is contained in:
Rene Gollent 2012-12-17 20:46:27 -05:00
parent c56757fb7c
commit 596922bb7f
4 changed files with 209 additions and 1 deletions

View File

@ -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

View File

@ -0,0 +1,172 @@
/*
* Copyright 2012, Rene Gollent, rene@gollent.com.
* Distributed under the terms of the MIT License.
*/
#include "CliPrintVariableCommand.h"
#include <stdio.h>
#include <AutoLocker.h>
#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<ValueNodeContainer> 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<ValueNodeContainer> 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;
}

View File

@ -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

View File

@ -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)