xref: /haiku/src/system/kernel/debug/debug_variables.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
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