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 19static const int kVariableCount = 64; 20static const int kTemporaryVariableCount = 32; 21static const char kTemporaryVariablePrefix = '_'; 22static const char kArchSpecificVariablePrefix = '$'; 23static const char kSymbolVariablePrefix = '@'; 24static const char* const kCommandReturnValueVariable = "_"; 25 26 27struct 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 52struct TemporaryVariable : Variable, 53 DoublyLinkedListLinkImpl<TemporaryVariable> { 54 bool queued; 55}; 56 57static Variable sVariables[kVariableCount]; 58static TemporaryVariable sTemporaryVariables[kTemporaryVariableCount]; 59 60static DoublyLinkedList<TemporaryVariable> sTemporaryVariablesLRUQueue; 61 62 63static inline bool 64is_temporary_variable(const char* variableName) 65{ 66 return variableName[0] == kTemporaryVariablePrefix; 67} 68 69 70static inline bool 71is_arch_specific_variable(const char* variableName) 72{ 73 return variableName[0] == kArchSpecificVariablePrefix; 74} 75 76 77static inline bool 78is_symbol_variable(const char* variableName) 79{ 80 return variableName[0] == kSymbolVariablePrefix; 81} 82 83 84static void 85dequeue_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 95static void 96unset_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 105static void 106touch_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 120static Variable* 121free_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 133static Variable* 134get_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 180static int 181cmd_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 199static int 200cmd_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 215static int 216cmd_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 250bool 251is_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 264bool 265set_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 283uint64 284get_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 307bool 308unset_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 319void 320unset_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 338void 339debug_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