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