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