Add CLI print variable command.
This commit is contained in:
parent
c56757fb7c
commit
596922bb7f
@ -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
|
||||
|
||||
|
172
src/apps/debugger/user_interface/cli/CliPrintVariableCommand.cpp
Normal file
172
src/apps/debugger/user_interface/cli/CliPrintVariableCommand.cpp
Normal 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;
|
||||
}
|
@ -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
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user