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
IsUsedVariable31 inline bool IsUsed() const
32 {
33 return name[0] != '\0';
34 }
35
InitVariable36 void Init(const char* variableName)
37 {
38 strlcpy(name, variableName, sizeof(name));
39 }
40
UninitVariable41 void Uninit()
42 {
43 name[0] = '\0';
44 }
45
HasNameVariable46 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
is_temporary_variable(const char * variableName)64 is_temporary_variable(const char* variableName)
65 {
66 return variableName[0] == kTemporaryVariablePrefix;
67 }
68
69
70 static inline bool
is_arch_specific_variable(const char * variableName)71 is_arch_specific_variable(const char* variableName)
72 {
73 return variableName[0] == kArchSpecificVariablePrefix;
74 }
75
76
77 static inline bool
is_symbol_variable(const char * variableName)78 is_symbol_variable(const char* variableName)
79 {
80 return variableName[0] == kSymbolVariablePrefix;
81 }
82
83
84 static void
dequeue_temporary_variable(TemporaryVariable * variable)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
unset_variable(Variable * variable)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
touch_variable(Variable * _variable)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*
free_temporary_variable_slot()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*
get_variable(const char * variableName,bool create)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
cmd_unset_variable(int argc,char ** argv)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
cmd_unset_all_variables(int argc,char ** argv)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
cmd_variables(int argc,char ** argv)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
is_debug_variable_defined(const char * variableName)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
set_debug_variable(const char * variableName,uint64 value)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
get_debug_variable(const char * variableName,uint64 defaultValue)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
unset_debug_variable(const char * variableName)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
unset_all_debug_variables()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
debug_variables_init()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