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