xref: /haiku/src/apps/debugger/user_interface/cli/commands/CliPrintVariableCommand.cpp (revision 45e0c33d4fdc8926a82c5800b7f7953f61f46afa)
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