xref: /haiku/src/apps/debugger/user_interface/cli/commands/CliPrintVariableCommand.cpp (revision 5e96d7d537fbec23bad4ae9b4c8e7b02e769f0c6)
1 /*
2  * Copyright 2012, Rene Gollent, rene@gollent.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "CliPrintVariableCommand.h"
8 
9 #include <stdio.h>
10 
11 #include <AutoLocker.h>
12 
13 #include "CliContext.h"
14 #include "StackFrame.h"
15 #include "StackTrace.h"
16 #include "Team.h"
17 #include "Type.h"
18 #include "UiUtils.h"
19 #include "UserInterface.h"
20 #include "ValueLoader.h"
21 #include "ValueLocation.h"
22 #include "ValueNode.h"
23 #include "ValueNodeContainer.h"
24 #include "ValueNodeManager.h"
25 
26 
27 CliPrintVariableCommand::CliPrintVariableCommand()
28 	:
29 	CliCommand("print value(s) of a variable",
30 		"%s [--depth n] variable [variable2 ...]\n"
31 		"Prints the value and members of the named variable.")
32 {
33 }
34 
35 
36 void
37 CliPrintVariableCommand::Execute(int argc, const char* const* argv,
38 	CliContext& context)
39 {
40 	if (argc < 2) {
41 		PrintUsage(argv[0]);
42 		return;
43 	}
44 
45 	ValueNodeManager* manager = context.GetValueNodeManager();
46 
47 	ValueNodeContainer* container = manager->GetContainer();
48 	AutoLocker<ValueNodeContainer> containerLocker(container);
49 	if (container == NULL || container->CountChildren() == 0) {
50 		printf("No variables available.\n");
51 		return;
52 	}
53 
54 	int32 depth = 1;
55 	int32 i = 1;
56 	for (; i < argc; i++) {
57 		if (strcmp(argv[i], "--depth") == 0) {
58 			if (i == argc - 1) {
59 				printf("Error: An argument must be supplied for depth.\n");
60 				return;
61 			}
62 			char* endPointer;
63 			depth = strtol(argv[i + 1], &endPointer, 0);
64 			if (*endPointer != '\0' || depth < 0) {
65 				printf("Error: Invalid parameter \"%s\"\n", argv[i + 1]);
66 				return;
67 			}
68 			i++;
69 		}
70 		else
71 			break;
72 	}
73 
74 	if (i == argc) {
75 		printf("Error: At least one variable name must be supplied.\n");
76 		return;
77 	}
78 
79 	bool found = false;
80 	while (i < argc) {
81 		// TODO: support variable expressions in addition to just names.
82 		const char* variableName = argv[i++];
83 		for (int32 j = 0; ValueNodeChild* child = container->ChildAt(j); j++) {
84 			if (child->Name() == variableName) {
85 				found = true;
86 				containerLocker.Unlock();
87 				_ResolveValueIfNeeded(child->Node(), context, depth);
88 				containerLocker.Lock();
89 				BString data;
90 				UiUtils::PrintValueNodeGraph(data, child, 1, depth);
91 				printf("%s", data.String());
92 			}
93 		}
94 
95 		if (!found)
96 			printf("No such variable: %s\n", variableName);
97 		found = false;
98 	}
99 }
100 
101 
102 status_t
103 CliPrintVariableCommand::_ResolveValueIfNeeded(ValueNode* node,
104 	CliContext& context, int32 maxDepth)
105 {
106 	StackFrame* frame = context.GetStackTrace()->FrameAt(
107 		context.CurrentStackFrameIndex());
108 	if (frame == NULL)
109 		return B_BAD_DATA;
110 
111 	status_t result = B_OK;
112 	ValueNodeManager* manager = context.GetValueNodeManager();
113 	ValueNodeContainer* container = manager->GetContainer();
114 	AutoLocker<ValueNodeContainer> containerLocker(container);
115 	if (node->LocationAndValueResolutionState() == VALUE_NODE_UNRESOLVED) {
116 		context.GetUserInterfaceListener()->ValueNodeValueRequested(
117 			context.CurrentThread()->GetCpuState(), container, node);
118 
119 
120 		while (node->LocationAndValueResolutionState()
121 			== VALUE_NODE_UNRESOLVED) {
122 			containerLocker.Unlock();
123 			context.WaitForEvents(CliContext::EVENT_VALUE_NODE_CHANGED);
124 			containerLocker.Lock();
125 			if (context.IsTerminating())
126 				return B_ERROR;
127 		}
128 	}
129 
130 	if (node->LocationAndValueResolutionState() == B_OK && maxDepth > 0) {
131 		for (int32 i = 0; i < node->CountChildren(); i++) {
132 			ValueNodeChild* child = node->ChildAt(i);
133 			containerLocker.Unlock();
134 			result = manager->AddChildNodes(child);
135 			if (result != B_OK)
136 				continue;
137 
138 			// since in the case of a pointer to a compound we hide
139 			// the intervening compound, don't consider the hidden node
140 			// a level for the purposes of depth traversal
141 			if (node->GetType()->Kind() == TYPE_ADDRESS
142 				&& child->GetType()->Kind() == TYPE_COMPOUND) {
143 				_ResolveValueIfNeeded(child->Node(), context, maxDepth);
144 			} else
145 				_ResolveValueIfNeeded(child->Node(), context, maxDepth - 1);
146 			containerLocker.Lock();
147 		}
148 	}
149 
150 	return result;
151 }
152