xref: /haiku/src/system/kernel/debug/debug_builtin_commands.cpp (revision 3aeed6607cd07762c0e709633c012b3a632dbad9)
1 /*
2  * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de
3  * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de
4  * Distributed under the terms of the MIT License.
5  *
6  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
7  * Distributed under the terms of the NewOS License.
8  */
9 
10 #include "debug_builtin_commands.h"
11 
12 #include <ctype.h>
13 #include <string.h>
14 #include <strings.h>
15 
16 #include <debug.h>
17 #include <kernel.h>
18 
19 #include "debug_commands.h"
20 #include "gdb.h"
21 
22 
23 static int
cmd_reboot(int argc,char ** argv)24 cmd_reboot(int argc, char **argv)
25 {
26 	arch_cpu_shutdown(true);
27 	return 0;
28 		// I'll be really suprised if this line ever runs! ;-)
29 }
30 
31 
32 static int
cmd_shutdown(int argc,char ** argv)33 cmd_shutdown(int argc, char **argv)
34 {
35 	arch_cpu_shutdown(false);
36 	return 0;
37 }
38 
39 
40 static int
cmd_help(int argc,char ** argv)41 cmd_help(int argc, char **argv)
42 {
43 	debugger_command *command, *specified = NULL;
44 	const char *start = NULL;
45 	int32 startLength = 0;
46 	bool ambiguous;
47 
48 	if (argc > 1) {
49 		specified = find_debugger_command(argv[1], false, ambiguous);
50 		if (specified == NULL) {
51 			start = argv[1];
52 			startLength = strlen(start);
53 		}
54 	}
55 
56 	if (specified != NULL) {
57 		// only print out the help of the specified command (and all of its aliases)
58 		kprintf("debugger command for \"%s\" and aliases:\n", specified->name);
59 	} else if (start != NULL)
60 		kprintf("debugger commands starting with \"%s\":\n", start);
61 	else
62 		kprintf("debugger commands:\n");
63 
64 	for (command = get_debugger_commands(); command != NULL;
65 			command = command->next) {
66 		if (specified && command->func != specified->func)
67 			continue;
68 		if (start != NULL && strncmp(start, command->name, startLength))
69 			continue;
70 
71 		kprintf(" %-20s\t\t%s\n", command->name, command->description ? command->description : "-");
72 	}
73 
74 	return 0;
75 }
76 
77 
78 static int
cmd_continue(int argc,char ** argv)79 cmd_continue(int argc, char **argv)
80 {
81 	return B_KDEBUG_QUIT;
82 }
83 
84 
85 static int
cmd_expr(int argc,char ** argv)86 cmd_expr(int argc, char **argv)
87 {
88 	if (argc != 2) {
89 		print_debugger_command_usage(argv[0]);
90 		return 0;
91 	}
92 
93 	uint64 result;
94 	if (evaluate_debug_expression(argv[1], &result, false)) {
95 		kprintf("%" B_PRIu64 " (0x%" B_PRIx64 ")\n", result, result);
96 		set_debug_variable("_", result);
97 	}
98 
99 	return 0;
100 }
101 
102 
103 static int
cmd_error(int argc,char ** argv)104 cmd_error(int argc, char **argv)
105 {
106 	if (argc != 2) {
107 		print_debugger_command_usage(argv[0]);
108 		return 0;
109 	}
110 
111 	int32 error = parse_expression(argv[1]);
112 	kprintf("error 0x%" B_PRIx32 ": %s\n", error, strerror(error));
113 
114 	return 0;
115 }
116 
117 
118 static int
cmd_head(int argc,char ** argv)119 cmd_head(int argc, char** argv)
120 {
121 	debugger_command_pipe_segment* segment
122 		= get_current_debugger_command_pipe_segment();
123 	if (segment == NULL) {
124 		kprintf_unfiltered("%s can only be run as part of a pipe!\n", argv[0]);
125 		return B_KDEBUG_ERROR;
126 	}
127 
128 	struct user_data {
129 		uint64	max_lines;
130 		uint64	lines;
131 	};
132 	user_data* userData = (user_data*)segment->user_data;
133 
134 	if (segment->invocations == 0) {
135 		if (argc != 3) {
136 			print_debugger_command_usage(argv[0]);
137 			return B_KDEBUG_ERROR;
138 		}
139 
140 		if (!evaluate_debug_expression(argv[1], &userData->max_lines, false))
141 			return B_KDEBUG_ERROR;
142 		userData->lines = 0;
143 	}
144 
145 	if (++userData->lines <= userData->max_lines) {
146 		kputs(argv[2]);
147 		kputs("\n");
148 	}
149 
150 	return 0;
151 }
152 
153 
154 static int
cmd_tail(int argc,char ** argv)155 cmd_tail(int argc, char** argv)
156 {
157 	debugger_command_pipe_segment* segment
158 		= get_current_debugger_command_pipe_segment();
159 	if (segment == NULL) {
160 		kprintf_unfiltered("%s can only be run as part of a pipe!\n", argv[0]);
161 		return B_KDEBUG_ERROR;
162 	}
163 
164 	struct user_data {
165 		uint64	max_lines;
166 		int64	line_count;
167 		bool	restarted;
168 	};
169 	user_data* userData = (user_data*)segment->user_data;
170 
171 	if (segment->invocations == 0) {
172 		if (argc > 3) {
173 			print_debugger_command_usage(argv[0]);
174 			return B_KDEBUG_ERROR;
175 		}
176 
177 		userData->max_lines = 10;
178 		if (argc > 2 && !evaluate_debug_expression(argv[1],
179 				&userData->max_lines, false)) {
180 			return B_KDEBUG_ERROR;
181 		}
182 
183 		userData->line_count = 1;
184 		userData->restarted = false;
185 	} else if (!userData->restarted) {
186 		if (argv[argc - 1] == NULL) {
187 			userData->restarted = true;
188 			userData->line_count -= userData->max_lines;
189 			return B_KDEBUG_RESTART_PIPE;
190 		}
191 
192 		++userData->line_count;
193 	} else {
194 		if (argv[argc - 1] == NULL)
195 			return 0;
196 
197 		if (--userData->line_count < 0) {
198 			kputs(argv[argc - 1]);
199 			kputs("\n");
200 		}
201 	}
202 
203 	return 0;
204 }
205 
206 
207 static int
cmd_grep(int argc,char ** argv)208 cmd_grep(int argc, char** argv)
209 {
210 	bool caseSensitive = true;
211 	bool inverseMatch = false;
212 
213 	int argi = 1;
214 	for (; argi < argc; argi++) {
215 		const char* arg = argv[argi];
216 		if (arg[0] != '-')
217 			break;
218 
219 		for (int32 i = 1; arg[i] != '\0'; i++) {
220 			if (arg[i] == 'i') {
221 				caseSensitive = false;
222 			} else if (arg[i] == 'v') {
223 				inverseMatch = true;
224 			} else {
225 				print_debugger_command_usage(argv[0]);
226 				return B_KDEBUG_ERROR;
227 			}
228 		}
229 	}
230 
231 	if (argc - argi != 2) {
232 		print_debugger_command_usage(argv[0]);
233 		return B_KDEBUG_ERROR;
234 	}
235 
236 	const char* pattern = argv[argi++];
237 	const char* line = argv[argi++];
238 
239 	bool match;
240 	if (caseSensitive) {
241 		match = strstr(line, pattern) != NULL;
242 	} else {
243 		match = false;
244 		int32 lineLen = strlen(line);
245 		int32 patternLen = strlen(pattern);
246 		for (int32 i = 0; i <= lineLen - patternLen; i++) {
247 			// This is rather slow, but should be OK for our purposes.
248 			if (strncasecmp(line + i, pattern, patternLen) == 0) {
249 				match = true;
250 				break;
251 			}
252 		}
253 	}
254 
255 	if (match != inverseMatch) {
256 		kputs(line);
257 		kputs("\n");
258 	}
259 
260 	return 0;
261 }
262 
263 
264 static int
cmd_wc(int argc,char ** argv)265 cmd_wc(int argc, char** argv)
266 {
267 	debugger_command_pipe_segment* segment
268 		= get_current_debugger_command_pipe_segment();
269 	if (segment == NULL) {
270 		kprintf_unfiltered("%s can only be run as part of a pipe!\n", argv[0]);
271 		return B_KDEBUG_ERROR;
272 	}
273 
274 	struct user_data {
275 		uint64	lines;
276 		uint64	words;
277 		uint64	chars;
278 	};
279 	user_data* userData = (user_data*)segment->user_data;
280 
281 	if (segment->invocations == 0) {
282 		if (argc != 2) {
283 			print_debugger_command_usage(argv[0]);
284 			return B_KDEBUG_ERROR;
285 		}
286 
287 		userData->lines = 0;
288 		userData->words = 0;
289 		userData->chars = 0;
290 	}
291 
292 	const char* line = argv[1];
293 	if (line == NULL) {
294 		// last run -- print results
295 		kprintf("%10" B_PRIu64 " %10" B_PRIu64 " %10" B_PRIu64 "\n",
296 			userData->lines, userData->words, userData->chars);
297 		return 0;
298 	}
299 
300 	userData->lines++;
301 	userData->chars++;
302 		// newline
303 
304 	// count words and chars in this line
305 	bool inWord = false;
306 	for (; *line != '\0'; line++) {
307 		userData->chars++;
308 		if ((isspace(*line) != 0) == inWord) {
309 			inWord = !inWord;
310 			if (inWord)
311 				userData->words++;
312 		}
313 	}
314 
315 	return 0;
316 }
317 
318 
319 static int
cmd_faults(int argc,char ** argv)320 cmd_faults(int argc, char** argv)
321 {
322 	if (argc > 2) {
323 		print_debugger_command_usage(argv[0]);
324 		return B_KDEBUG_ERROR;
325 	}
326 
327 	if (argc == 2)
328 		gInvokeCommandDirectly = parse_expression(argv[1]) == 0;
329 
330 	kprintf("Fault handling is %s%s.\n", argc == 2 ? "now " : "",
331 		gInvokeCommandDirectly ? "off" : "on");
332 	return 0;
333 }
334 
335 
336 // #pragma mark -
337 
338 
339 void
debug_builtin_commands_init()340 debug_builtin_commands_init()
341 {
342 	add_debugger_command_etc("help", &cmd_help, "List all debugger commands",
343 		"[name]\n"
344 		"Lists all debugger commands or those starting with \"name\".\n", 0);
345 	add_debugger_command_etc("reboot", &cmd_reboot, "Reboot the system",
346 		"\n"
347 		"Reboots the system.\n", 0);
348 	add_debugger_command_etc("shutdown", &cmd_shutdown, "Shut down the system",
349 		"\n"
350 		"Shuts down the system.\n", 0);
351 	add_debugger_command_etc("gdb", &cmd_gdb, "Connect to remote gdb",
352 		"\n"
353 		"Connects to a remote gdb connected to the serial port.\n", 0);
354 	add_debugger_command_etc("continue", &cmd_continue, "Leave kernel debugger",
355 		"\n"
356 		"Leaves kernel debugger.\n", 0);
357 	add_debugger_command_alias("exit", "continue", "Same as \"continue\"");
358 	add_debugger_command_alias("es", "continue", "Same as \"continue\"");
359 	add_debugger_command_etc("expr", &cmd_expr,
360 		"Evaluates the given expression and prints the result",
361 		"<expression>\n"
362 		"Evaluates the given expression and prints the result.\n",
363 		B_KDEBUG_DONT_PARSE_ARGUMENTS);
364 	add_debugger_command_etc("error", &cmd_error,
365 		"Prints a human-readable description for an error code",
366 		"<error>\n"
367 		"Prints a human-readable description for the given numeric error\n"
368 		"code.\n"
369 		"  <error>  - The numeric error code.\n", 0);
370 	add_debugger_command_etc("faults", &cmd_faults, "Toggles fault handling "
371 		"for debugger commands",
372 		"[0|1]\n"
373 		"Toggles fault handling on (1) or off (0).\n", 0);
374 	add_debugger_command_etc("head", &cmd_head,
375 		"Prints only the first lines of output from another command",
376 		"<maxLines>\n"
377 		"Should be used in a command pipe. It prints only the first\n"
378 		"<maxLines> lines of output from the previous command in the pipe and\n"
379 		"silently discards the rest of the output.\n", 0);
380 	add_debugger_command_etc("tail", &cmd_tail,
381 		"Prints only the last lines of output from another command",
382 		"[ <maxLines> ]\n"
383 		"Should be used in a command pipe. It prints only the last\n"
384 		"<maxLines> (default 10) lines of output from the previous command in\n"
385 		"the pipe and silently discards the rest of the output.\n",
386 		B_KDEBUG_PIPE_FINAL_RERUN);
387 	add_debugger_command_etc("grep", &cmd_grep,
388 		"Filters output from another command",
389 		"[ -i ] [ -v ] <pattern>\n"
390 		"Should be used in a command pipe. It filters all output from the\n"
391 		"previous command in the pipe according to the given pattern.\n"
392 		"When \"-v\" is specified, only those lines are printed that don't\n"
393 		"match the given pattern, otherwise only those that do match. When\n"
394 		"\"-i\" is specified, the pattern is matched case insensitive,\n"
395 		"otherwise case sensitive.\n", 0);
396 	add_debugger_command_etc("wc", &cmd_wc,
397 		"Counts the lines, words, and characters of another command's output",
398 		"<maxLines>\n"
399 		"Should be used in a command pipe. It prints how many lines, words,\n"
400 		"and characters the output of the previous command consists of.\n",
401 		B_KDEBUG_PIPE_FINAL_RERUN);
402 }
403