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