Add CLI print variable command.
This commit is contained in:
@@ -193,12 +193,13 @@ Application Debugger :
|
|||||||
CliContext.cpp
|
CliContext.cpp
|
||||||
CliContinueCommand.cpp
|
CliContinueCommand.cpp
|
||||||
CliDebugReportCommand.cpp
|
CliDebugReportCommand.cpp
|
||||||
|
CliPrintVariableCommand.cpp
|
||||||
|
CliQuitCommand.cpp
|
||||||
CliStackFrameCommand.cpp
|
CliStackFrameCommand.cpp
|
||||||
CliStackTraceCommand.cpp
|
CliStackTraceCommand.cpp
|
||||||
CliStopCommand.cpp
|
CliStopCommand.cpp
|
||||||
CliThreadCommand.cpp
|
CliThreadCommand.cpp
|
||||||
CliThreadsCommand.cpp
|
CliThreadsCommand.cpp
|
||||||
CliQuitCommand.cpp
|
|
||||||
CliVariablesCommand.cpp
|
CliVariablesCommand.cpp
|
||||||
CommandLineUserInterface.cpp
|
CommandLineUserInterface.cpp
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
|
* 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
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "CliContext.h"
|
#include "CliContext.h"
|
||||||
#include "CliContinueCommand.h"
|
#include "CliContinueCommand.h"
|
||||||
#include "CliDebugReportCommand.h"
|
#include "CliDebugReportCommand.h"
|
||||||
|
#include "CliPrintVariableCommand.h"
|
||||||
#include "CliQuitCommand.h"
|
#include "CliQuitCommand.h"
|
||||||
#include "CliStackFrameCommand.h"
|
#include "CliStackFrameCommand.h"
|
||||||
#include "CliStackTraceCommand.h"
|
#include "CliStackTraceCommand.h"
|
||||||
@@ -313,6 +314,7 @@ CommandLineUserInterface::_RegisterCommands()
|
|||||||
&& _RegisterCommand("continue", new(std::nothrow) CliContinueCommand)
|
&& _RegisterCommand("continue", new(std::nothrow) CliContinueCommand)
|
||||||
&& _RegisterCommand("frame", new(std::nothrow) CliStackFrameCommand)
|
&& _RegisterCommand("frame", new(std::nothrow) CliStackFrameCommand)
|
||||||
&& _RegisterCommand("help", new(std::nothrow) HelpCommand(this))
|
&& _RegisterCommand("help", new(std::nothrow) HelpCommand(this))
|
||||||
|
&& _RegisterCommand("print", new(std::nothrow) CliPrintVariableCommand)
|
||||||
&& _RegisterCommand("quit", new(std::nothrow) CliQuitCommand)
|
&& _RegisterCommand("quit", new(std::nothrow) CliQuitCommand)
|
||||||
&& _RegisterCommand("save-report",
|
&& _RegisterCommand("save-report",
|
||||||
new(std::nothrow) CliDebugReportCommand)
|
new(std::nothrow) CliDebugReportCommand)
|
||||||
|
|||||||
Reference in New Issue
Block a user