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 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 33 cmd_shutdown(int argc, char **argv) 34 { 35 arch_cpu_shutdown(false); 36 return 0; 37 } 38 39 40 static int 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 79 cmd_continue(int argc, char **argv) 80 { 81 return B_KDEBUG_QUIT; 82 } 83 84 85 static int 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 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 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 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 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 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 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 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