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