1 /* 2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "debug_variables.h" 7 8 #include <string.h> 9 10 #include <KernelExport.h> 11 12 #include <arch/debug.h> 13 #include <debug.h> 14 #include <util/DoublyLinkedList.h> 15 16 17 static const int kVariableCount = 64; 18 static const int kTemporaryVariableCount = 32; 19 static const char kTemporaryVariablePrefix = '_'; 20 static const char kArchSpecificVariablePrefix = '$'; 21 static const char* const kCommandReturnValueVariable = "_"; 22 23 24 struct Variable { 25 char name[MAX_DEBUG_VARIABLE_NAME_LEN]; 26 uint64 value; 27 28 inline bool IsUsed() const 29 { 30 return name[0] != '\0'; 31 } 32 33 void Init(const char* variableName) 34 { 35 strlcpy(name, variableName, sizeof(name)); 36 } 37 38 void Uninit() 39 { 40 name[0] = '\0'; 41 } 42 43 inline bool HasName(const char* variableName) const 44 { 45 return strncmp(name, variableName, sizeof(name)) == 0; 46 } 47 }; 48 49 struct TemporaryVariable : Variable, 50 DoublyLinkedListLinkImpl<TemporaryVariable> { 51 }; 52 53 static Variable sVariables[kVariableCount]; 54 static TemporaryVariable sTemporaryVariables[kTemporaryVariableCount]; 55 56 static DoublyLinkedList<TemporaryVariable> sTemporaryVariablesLRUQueue; 57 58 59 static inline bool 60 is_temporary_variable(const char* variableName) 61 { 62 return variableName[0] == kTemporaryVariablePrefix; 63 } 64 65 66 static inline bool 67 is_arch_specific_variable(const char* variableName) 68 { 69 return variableName[0] == kArchSpecificVariablePrefix; 70 } 71 72 73 static void 74 dequeue_temporary_variable(TemporaryVariable* variable) 75 { 76 // dequeue if queued 77 if (variable->GetDoublyLinkedListLink()->previous != NULL 78 || sTemporaryVariablesLRUQueue.Head() == variable) { 79 sTemporaryVariablesLRUQueue.Remove(variable); 80 } 81 } 82 83 84 static void 85 unset_variable(Variable* variable) 86 { 87 if (is_temporary_variable(variable->name)) 88 dequeue_temporary_variable(static_cast<TemporaryVariable*>(variable)); 89 90 variable->Uninit(); 91 } 92 93 94 static void 95 touch_variable(Variable* _variable) 96 { 97 if (!is_temporary_variable(_variable->name)) 98 return; 99 100 TemporaryVariable* variable = static_cast<TemporaryVariable*>(_variable); 101 102 // move to the end of the queue 103 dequeue_temporary_variable(variable); 104 sTemporaryVariablesLRUQueue.Add(variable); 105 } 106 107 108 static Variable* 109 free_temporary_variable_slot() 110 { 111 TemporaryVariable* variable = sTemporaryVariablesLRUQueue.RemoveHead(); 112 if (variable) 113 variable->Uninit(); 114 115 return variable; 116 } 117 118 119 static Variable* 120 get_variable(const char* variableName, bool create) 121 { 122 // find the variable in the respective array and a free slot, we can 123 // use, if it doesn't exist yet 124 Variable* freeSlot = NULL; 125 126 if (is_temporary_variable(variableName)) { 127 // temporary variable 128 for (int i = 0; i < kTemporaryVariableCount; i++) { 129 TemporaryVariable* variable = sTemporaryVariables + i; 130 131 if (!variable->IsUsed()) { 132 if (freeSlot == NULL) 133 freeSlot = variable; 134 } else if (variable->HasName(variableName)) 135 return variable; 136 } 137 138 if (create && freeSlot == NULL) 139 freeSlot = free_temporary_variable_slot(); 140 } else { 141 // persistent variable 142 for (int i = 0; i < kVariableCount; i++) { 143 Variable* variable = sVariables + i; 144 145 if (!variable->IsUsed()) { 146 if (freeSlot == NULL) 147 freeSlot = variable; 148 } else if (variable->HasName(variableName)) 149 return variable; 150 } 151 } 152 153 154 if (create && freeSlot != NULL) { 155 freeSlot->Init(variableName); 156 return freeSlot; 157 } 158 159 return NULL; 160 } 161 162 163 // #pragma mark - debugger commands 164 165 166 static int 167 cmd_unset_variable(int argc, char **argv) 168 { 169 static const char* usage = "usage: unset <variable>\n" 170 "Unsets the given variable, if it exists.\n"; 171 if (argc != 2 || strcmp(argv[1], "--help") == 0) { 172 kprintf(usage); 173 return 0; 174 } 175 176 const char* variable = argv[1]; 177 178 if (!unset_debug_variable(variable)) 179 kprintf("Did not find variable %s.\n", variable); 180 181 return 0; 182 } 183 184 185 static int 186 cmd_unset_all_variables(int argc, char **argv) 187 { 188 static const char* usage = "usage: %s\n" 189 "Unsets all variables.\n"; 190 if (argc == 2 && strcmp(argv[1], "--help") == 0) { 191 kprintf(usage, argv[0]); 192 return 0; 193 } 194 195 unset_all_debug_variables(); 196 197 return 0; 198 } 199 200 201 static int 202 cmd_variables(int argc, char **argv) 203 { 204 static const char* usage = "usage: vars\n" 205 "Unsets the given variable, if it exists.\n"; 206 if (argc != 1) { 207 kprintf(usage); 208 return 0; 209 } 210 211 // persistent variables 212 for (int i = 0; i < kVariableCount; i++) { 213 Variable& variable = sVariables[i]; 214 if (variable.IsUsed()) { 215 kprintf("%16s: %llu (0x%llx)\n", variable.name, variable.value, 216 variable.value); 217 } 218 } 219 220 // temporary variables 221 for (int i = 0; i < kTemporaryVariableCount; i++) { 222 Variable& variable = sTemporaryVariables[i]; 223 if (variable.IsUsed()) { 224 kprintf("%16s: %llu (0x%llx)\n", variable.name, variable.value, 225 variable.value); 226 } 227 } 228 229 return 0; 230 } 231 232 233 // #pragma mark - kernel public functions 234 235 236 bool 237 is_debug_variable_defined(const char* variableName) 238 { 239 if (get_variable(variableName, false) != NULL) 240 return true; 241 242 return is_arch_specific_variable(variableName) 243 && arch_is_debug_variable_defined(variableName + 1); 244 } 245 246 247 bool 248 set_debug_variable(const char* variableName, uint64 value) 249 { 250 if (is_arch_specific_variable(variableName)) 251 return arch_set_debug_variable(variableName + 1, value) == B_OK; 252 253 if (Variable* variable = get_variable(variableName, true)) { 254 variable->value = value; 255 touch_variable(variable); 256 return true; 257 } 258 259 return false; 260 } 261 262 263 uint64 264 get_debug_variable(const char* variableName, uint64 defaultValue) 265 { 266 if (Variable* variable = get_variable(variableName, false)) { 267 touch_variable(variable); 268 return variable->value; 269 } 270 271 uint64 value; 272 if (is_arch_specific_variable(variableName) 273 && arch_get_debug_variable(variableName + 1, &value) == B_OK) { 274 return value; 275 } 276 277 return defaultValue; 278 } 279 280 281 bool 282 unset_debug_variable(const char* variableName) 283 { 284 if (Variable* variable = get_variable(variableName, false)) { 285 unset_variable(variable); 286 return true; 287 } 288 289 return false; 290 } 291 292 293 void 294 unset_all_debug_variables() 295 { 296 // persistent variables 297 for (int i = 0; i < kVariableCount; i++) { 298 Variable& variable = sVariables[i]; 299 if (variable.IsUsed()) 300 unset_variable(&variable); 301 } 302 303 // temporary variables 304 for (int i = 0; i < kTemporaryVariableCount; i++) { 305 Variable& variable = sTemporaryVariables[i]; 306 if (variable.IsUsed()) 307 unset_variable(&variable); 308 } 309 } 310 311 312 void 313 debug_variables_init() 314 { 315 add_debugger_command("unset", &cmd_unset_variable, 316 "Unsets the given variable"); 317 add_debugger_command("unset_all", &cmd_unset_all_variables, 318 "Unsets all variables"); 319 add_debugger_command("vars", &cmd_variables, 320 "Lists all defined variables with their values"); 321 } 322