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