144646df4SRene Gollent /*
2fce4895dSRene Gollent * Copyright 2012-2016, Rene Gollent, rene@gollent.com.
344646df4SRene Gollent * Distributed under the terms of the MIT License.
444646df4SRene Gollent */
544646df4SRene Gollent
644646df4SRene Gollent
744646df4SRene Gollent #include "CliPrintVariableCommand.h"
844646df4SRene Gollent
944646df4SRene Gollent #include <stdio.h>
1044646df4SRene Gollent
1144646df4SRene Gollent #include <AutoLocker.h>
1244646df4SRene Gollent
1344646df4SRene Gollent #include "CliContext.h"
1444646df4SRene Gollent #include "StackFrame.h"
1544646df4SRene Gollent #include "StackTrace.h"
1644646df4SRene Gollent #include "Team.h"
1744646df4SRene Gollent #include "Type.h"
1844646df4SRene Gollent #include "UiUtils.h"
1944646df4SRene Gollent #include "UserInterface.h"
2044646df4SRene Gollent #include "ValueLocation.h"
2144646df4SRene Gollent #include "ValueNode.h"
2244646df4SRene Gollent #include "ValueNodeContainer.h"
2344646df4SRene Gollent #include "ValueNodeManager.h"
2444646df4SRene Gollent
2544646df4SRene Gollent
CliPrintVariableCommand()2644646df4SRene Gollent CliPrintVariableCommand::CliPrintVariableCommand()
2744646df4SRene Gollent :
2844646df4SRene Gollent CliCommand("print value(s) of a variable",
2944646df4SRene Gollent "%s [--depth n] variable [variable2 ...]\n"
3044646df4SRene Gollent "Prints the value and members of the named variable.")
3144646df4SRene Gollent {
3244646df4SRene Gollent }
3344646df4SRene Gollent
3444646df4SRene Gollent
3544646df4SRene Gollent void
Execute(int argc,const char * const * argv,CliContext & context)3644646df4SRene Gollent CliPrintVariableCommand::Execute(int argc, const char* const* argv,
3744646df4SRene Gollent CliContext& context)
3844646df4SRene Gollent {
3944646df4SRene Gollent if (argc < 2) {
4044646df4SRene Gollent PrintUsage(argv[0]);
4144646df4SRene Gollent return;
4244646df4SRene Gollent }
4344646df4SRene Gollent
4444646df4SRene Gollent ValueNodeManager* manager = context.GetValueNodeManager();
4544646df4SRene Gollent
4644646df4SRene Gollent ValueNodeContainer* container = manager->GetContainer();
4744646df4SRene Gollent AutoLocker<ValueNodeContainer> containerLocker(container);
4844646df4SRene Gollent if (container == NULL || container->CountChildren() == 0) {
4944646df4SRene Gollent printf("No variables available.\n");
5044646df4SRene Gollent return;
5144646df4SRene Gollent }
5244646df4SRene Gollent
5344646df4SRene Gollent int32 depth = 1;
5444646df4SRene Gollent int32 i = 1;
5544646df4SRene Gollent for (; i < argc; i++) {
5644646df4SRene Gollent if (strcmp(argv[i], "--depth") == 0) {
5744646df4SRene Gollent if (i == argc - 1) {
5844646df4SRene Gollent printf("Error: An argument must be supplied for depth.\n");
5944646df4SRene Gollent return;
6044646df4SRene Gollent }
6144646df4SRene Gollent char* endPointer;
6244646df4SRene Gollent depth = strtol(argv[i + 1], &endPointer, 0);
6344646df4SRene Gollent if (*endPointer != '\0' || depth < 0) {
6444646df4SRene Gollent printf("Error: Invalid parameter \"%s\"\n", argv[i + 1]);
6544646df4SRene Gollent return;
6644646df4SRene Gollent }
6744646df4SRene Gollent i++;
6844646df4SRene Gollent }
6944646df4SRene Gollent else
7044646df4SRene Gollent break;
7144646df4SRene Gollent }
7244646df4SRene Gollent
7344646df4SRene Gollent if (i == argc) {
7444646df4SRene Gollent printf("Error: At least one variable name must be supplied.\n");
7544646df4SRene Gollent return;
7644646df4SRene Gollent }
7744646df4SRene Gollent
7844646df4SRene Gollent bool found = false;
7944646df4SRene Gollent while (i < argc) {
8044646df4SRene Gollent // TODO: support variable expressions in addition to just names.
8144646df4SRene Gollent const char* variableName = argv[i++];
8244646df4SRene Gollent for (int32 j = 0; ValueNodeChild* child = container->ChildAt(j); j++) {
8344646df4SRene Gollent if (child->Name() == variableName) {
8444646df4SRene Gollent found = true;
8544646df4SRene Gollent containerLocker.Unlock();
8644646df4SRene Gollent _ResolveValueIfNeeded(child->Node(), context, depth);
8744646df4SRene Gollent containerLocker.Lock();
8844646df4SRene Gollent BString data;
8944646df4SRene Gollent UiUtils::PrintValueNodeGraph(data, child, 1, depth);
9044646df4SRene Gollent printf("%s", data.String());
9144646df4SRene Gollent }
9244646df4SRene Gollent }
9344646df4SRene Gollent
9444646df4SRene Gollent if (!found)
9544646df4SRene Gollent printf("No such variable: %s\n", variableName);
9644646df4SRene Gollent found = false;
9744646df4SRene Gollent }
9844646df4SRene Gollent }
9944646df4SRene Gollent
10044646df4SRene Gollent
10144646df4SRene Gollent status_t
_ResolveValueIfNeeded(ValueNode * node,CliContext & context,int32 maxDepth)10244646df4SRene Gollent CliPrintVariableCommand::_ResolveValueIfNeeded(ValueNode* node,
10344646df4SRene Gollent CliContext& context, int32 maxDepth)
10444646df4SRene Gollent {
10544646df4SRene Gollent StackFrame* frame = context.GetStackTrace()->FrameAt(
10644646df4SRene Gollent context.CurrentStackFrameIndex());
10744646df4SRene Gollent if (frame == NULL)
10844646df4SRene Gollent return B_BAD_DATA;
10944646df4SRene Gollent
11044646df4SRene Gollent status_t result = B_OK;
11144646df4SRene Gollent ValueNodeManager* manager = context.GetValueNodeManager();
11244646df4SRene Gollent ValueNodeContainer* container = manager->GetContainer();
11344646df4SRene Gollent AutoLocker<ValueNodeContainer> containerLocker(container);
11444646df4SRene Gollent if (node->LocationAndValueResolutionState() == VALUE_NODE_UNRESOLVED) {
11544646df4SRene Gollent context.GetUserInterfaceListener()->ValueNodeValueRequested(
11644646df4SRene Gollent context.CurrentThread()->GetCpuState(), container, node);
11744646df4SRene Gollent
11844646df4SRene Gollent
11944646df4SRene Gollent while (node->LocationAndValueResolutionState()
12044646df4SRene Gollent == VALUE_NODE_UNRESOLVED) {
12144646df4SRene Gollent containerLocker.Unlock();
122*45e0c33dSZardshard context.WaitForEvent(CliContext::MSG_VALUE_NODE_CHANGED);
12344646df4SRene Gollent containerLocker.Lock();
12444646df4SRene Gollent if (context.IsTerminating())
12544646df4SRene Gollent return B_ERROR;
12644646df4SRene Gollent }
12744646df4SRene Gollent }
12844646df4SRene Gollent
12944646df4SRene Gollent if (node->LocationAndValueResolutionState() == B_OK && maxDepth > 0) {
13044646df4SRene Gollent for (int32 i = 0; i < node->CountChildren(); i++) {
13144646df4SRene Gollent ValueNodeChild* child = node->ChildAt(i);
13244646df4SRene Gollent containerLocker.Unlock();
13344646df4SRene Gollent result = manager->AddChildNodes(child);
13444646df4SRene Gollent if (result != B_OK)
13544646df4SRene Gollent continue;
13644646df4SRene Gollent
13744646df4SRene Gollent // since in the case of a pointer to a compound we hide
13844646df4SRene Gollent // the intervening compound, don't consider the hidden node
13944646df4SRene Gollent // a level for the purposes of depth traversal
14044646df4SRene Gollent if (node->GetType()->Kind() == TYPE_ADDRESS
14144646df4SRene Gollent && child->GetType()->Kind() == TYPE_COMPOUND) {
14244646df4SRene Gollent _ResolveValueIfNeeded(child->Node(), context, maxDepth);
14344646df4SRene Gollent } else
14444646df4SRene Gollent _ResolveValueIfNeeded(child->Node(), context, maxDepth - 1);
14544646df4SRene Gollent containerLocker.Lock();
14644646df4SRene Gollent }
14744646df4SRene Gollent }
14844646df4SRene Gollent
14944646df4SRene Gollent return result;
15044646df4SRene Gollent }
151