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