1 /* 2 * Mach Operating System 3 * Copyright (c) 1991,1990 Carnegie Mellon University 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify and distribute this software and its 7 * documentation is hereby granted, provided that both the copyright 8 * notice and this permission notice appear in all copies of the 9 * software, derivative works or modified versions, and any portions 10 * thereof, and that both notices appear in supporting documentation. 11 * 12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15 * 16 * Carnegie Mellon requests users of this software to return to 17 * 18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19 * School of Computer Science 20 * Carnegie Mellon University 21 * Pittsburgh PA 15213-3890 22 * 23 * any improvements or extensions that they make and grant Carnegie the 24 * rights to redistribute these changes. 25 */ 26 /* 27 * db_command.c,v 1.3 1993/05/20 03:39:10 cgd Exp 28 * 29 * HISTORY 30 * db_command.c,v 31 * Revision 1.3 1993/05/20 03:39:10 cgd 32 * add explicit rcs id 33 * 34 * Revision 1.2 1993/03/21 18:08:04 cgd 35 * after 0.2.2 "stable" patches applied 36 * 37 * Revision 1.1.1.1 93/03/21 09:46:26 cgd 38 * initial import of 386bsd-0.1 sources 39 * 40 * Revision 1.1 1992/03/25 21:45:02 pace 41 * Initial revision 42 * 43 * Revision 2.6 91/02/05 17:06:10 mrt 44 * Changed to new Mach copyright 45 * [91/01/31 16:17:18 mrt] 46 * 47 * Revision 2.5 91/01/08 17:31:54 rpd 48 * Forward reference for db_fncall(); 49 * [91/01/04 12:35:17 rvb] 50 * 51 * Add call as a synonym for ! and match for next 52 * [91/01/04 12:14:48 rvb] 53 * 54 * Revision 2.4 90/11/07 16:49:15 rpd 55 * Added search. 56 * [90/11/06 rpd] 57 * 58 * Revision 2.3 90/10/25 14:43:45 rwd 59 * Changed db_fncall to print the result unsigned. 60 * [90/10/19 rpd] 61 * 62 * Added CS_MORE to db_watchpoint_cmd. 63 * [90/10/17 rpd] 64 * Added watchpoint commands: watch, dwatch, show watches. 65 * [90/10/16 rpd] 66 * 67 * Revision 2.2 90/08/27 21:50:10 dbg 68 * Remove 'listbreaks' - use 'show breaks' instead. Change 'show 69 * threads' to 'show all threads' to avoid clash with 'show thread'. 70 * Set 'dot' here from db_prev or db_next, depending on 'db_ed_style' 71 * flag and syntax table. 72 * [90/08/22 dbg] 73 * Reduce lint. 74 * [90/08/07 dbg] 75 * Created. 76 * [90/07/25 dbg] 77 * 78 */ 79 /* 80 * Author: David B. Golub, Carnegie Mellon University 81 * Date: 7/90 82 */ 83 /* 84 * Command dispatcher. 85 */ 86 #include "param.h" 87 #include "proc.h" 88 #include <machine/db_machdep.h> /* type definitions */ 89 90 #include <ddb/db_lex.h> 91 #include <ddb/db_output.h> 92 93 #include <setjmp.h> 94 95 /* 96 * Exported global variables 97 */ 98 boolean_t db_cmd_loop_done; 99 jmp_buf db_jmpbuf; 100 db_addr_t db_dot; 101 db_addr_t db_last_addr; 102 db_addr_t db_prev; 103 db_addr_t db_next; 104 105 /* 106 * if 'ed' style: 'dot' is set at start of last item printed, 107 * and '+' points to next line. 108 * Otherwise: 'dot' points to next item, '..' points to last. 109 */ 110 boolean_t db_ed_style = TRUE; 111 112 113 /* 114 * Utility routine - discard tokens through end-of-line. 115 */ 116 void 117 db_skip_to_eol() 118 { 119 int t; 120 do { 121 t = db_read_token(); 122 } while (t != tEOL); 123 } 124 125 /* 126 * Command table 127 */ 128 struct command { 129 char * name; /* command name */ 130 void (*fcn)(); /* function to call */ 131 int flag; /* extra info: */ 132 #define CS_OWN 0x1 /* non-standard syntax */ 133 #define CS_MORE 0x2 /* standard syntax, but may have other 134 words at end */ 135 #define CS_SET_DOT 0x100 /* set dot after command */ 136 struct command *more; /* another level of command */ 137 }; 138 139 /* 140 * Results of command search. 141 */ 142 #define CMD_UNIQUE 0 143 #define CMD_FOUND 1 144 #define CMD_NONE 2 145 #define CMD_AMBIGUOUS 3 146 #define CMD_HELP 4 147 148 /* 149 * Search for command prefix. 150 */ 151 int 152 db_cmd_search(name, table, cmdp) 153 char * name; 154 struct command *table; 155 struct command **cmdp; /* out */ 156 { 157 struct command *cmd; 158 int result = CMD_NONE; 159 160 for (cmd = table; cmd->name != 0; cmd++) { 161 register char *lp; 162 register char *rp; 163 register int c; 164 165 lp = name; 166 rp = cmd->name; 167 while ((c = *lp) == *rp) { 168 if (c == 0) { 169 /* complete match */ 170 *cmdp = cmd; 171 return (CMD_UNIQUE); 172 } 173 lp++; 174 rp++; 175 } 176 if (c == 0) { 177 /* end of name, not end of command - 178 partial match */ 179 if (result == CMD_FOUND) { 180 result = CMD_AMBIGUOUS; 181 /* but keep looking for a full match - 182 this lets us match single letters */ 183 } 184 else { 185 *cmdp = cmd; 186 result = CMD_FOUND; 187 } 188 } 189 } 190 if (result == CMD_NONE) { 191 /* check for 'help' */ 192 if (name[0] == 'h' && name[1] == 'e' 193 && name[2] == 'l' && name[3] == 'p') 194 result = CMD_HELP; 195 } 196 return (result); 197 } 198 199 void 200 db_cmd_list(table) 201 struct command *table; 202 { 203 register struct command *cmd; 204 205 for (cmd = table; cmd->name != 0; cmd++) { 206 db_printf("%-12s", cmd->name); 207 db_end_line(); 208 } 209 } 210 211 void 212 db_command(last_cmdp, cmd_table) 213 struct command **last_cmdp; /* IN_OUT */ 214 struct command *cmd_table; 215 { 216 struct command *cmd; 217 int t; 218 char modif[TOK_STRING_SIZE]; 219 db_expr_t addr, count; 220 boolean_t have_addr; 221 int result; 222 223 t = db_read_token(); 224 if (t == tEOL) { 225 /* empty line repeats last command, at 'next' */ 226 cmd = *last_cmdp; 227 addr = (db_expr_t)db_next; 228 have_addr = FALSE; 229 count = 1; 230 modif[0] = '\0'; 231 } 232 else if (t == tEXCL) { 233 void db_fncall(); 234 db_fncall(); 235 return; 236 } 237 else if (t != tIDENT) { 238 db_printf("?\n"); 239 db_flush_lex(); 240 return; 241 } 242 else { 243 /* 244 * Search for command 245 */ 246 while (cmd_table) { 247 result = db_cmd_search(db_tok_string, 248 cmd_table, 249 &cmd); 250 switch (result) { 251 case CMD_NONE: 252 db_printf("No such command\n"); 253 db_flush_lex(); 254 return; 255 case CMD_AMBIGUOUS: 256 db_printf("Ambiguous\n"); 257 db_flush_lex(); 258 return; 259 case CMD_HELP: 260 db_cmd_list(cmd_table); 261 db_flush_lex(); 262 return; 263 default: 264 break; 265 } 266 if ((cmd_table = cmd->more) != 0) { 267 t = db_read_token(); 268 if (t != tIDENT) { 269 db_cmd_list(cmd_table); 270 db_flush_lex(); 271 return; 272 } 273 } 274 } 275 276 if ((cmd->flag & CS_OWN) == 0) { 277 /* 278 * Standard syntax: 279 * command [/modifier] [addr] [,count] 280 */ 281 t = db_read_token(); 282 if (t == tSLASH) { 283 t = db_read_token(); 284 if (t != tIDENT) { 285 db_printf("Bad modifier\n"); 286 db_flush_lex(); 287 return; 288 } 289 db_strcpy(modif, db_tok_string); 290 } 291 else { 292 db_unread_token(t); 293 modif[0] = '\0'; 294 } 295 296 if (db_expression(&addr)) { 297 db_dot = (db_addr_t) addr; 298 db_last_addr = db_dot; 299 have_addr = TRUE; 300 } 301 else { 302 addr = (db_expr_t) db_dot; 303 have_addr = FALSE; 304 } 305 t = db_read_token(); 306 if (t == tCOMMA) { 307 if (!db_expression(&count)) { 308 db_printf("Count missing\n"); 309 db_flush_lex(); 310 return; 311 } 312 } 313 else { 314 db_unread_token(t); 315 count = -1; 316 } 317 if ((cmd->flag & CS_MORE) == 0) { 318 db_skip_to_eol(); 319 } 320 } 321 } 322 *last_cmdp = cmd; 323 if (cmd != 0) { 324 /* 325 * Execute the command. 326 */ 327 (*cmd->fcn)(addr, have_addr, count, modif); 328 329 if (cmd->flag & CS_SET_DOT) { 330 /* 331 * If command changes dot, set dot to 332 * previous address displayed (if 'ed' style). 333 */ 334 if (db_ed_style) { 335 db_dot = db_prev; 336 } 337 else { 338 db_dot = db_next; 339 } 340 } 341 else { 342 /* 343 * If command does not change dot, 344 * set 'next' location to be the same. 345 */ 346 db_next = db_dot; 347 } 348 } 349 } 350 351 /*ARGSUSED*/ 352 void 353 db_map_print_cmd(addr, have_addr, count, modif) 354 db_expr_t addr; 355 int have_addr; 356 db_expr_t count; 357 char * modif; 358 { 359 extern void vm_map_print(); 360 boolean_t full = FALSE; 361 362 if (modif[0] == 'f') 363 full = TRUE; 364 365 vm_map_print(addr, full); 366 } 367 368 /*ARGSUSED*/ 369 void 370 db_object_print_cmd(addr, have_addr, count, modif) 371 db_expr_t addr; 372 int have_addr; 373 db_expr_t count; 374 char * modif; 375 { 376 extern void vm_object_print(); 377 boolean_t full = FALSE; 378 379 if (modif[0] == 'f') 380 full = TRUE; 381 382 vm_object_print(addr, full); 383 } 384 385 /* 386 * 'show' commands 387 */ 388 extern void db_show_all_procs(); 389 extern void db_listbreak_cmd(); 390 extern void db_listwatch_cmd(); 391 extern void db_show_regs(); 392 void db_show_help(); 393 394 struct command db_show_all_cmds[] = { 395 { "procs", db_show_all_procs,0, 0 }, 396 { (char *)0 } 397 }; 398 399 struct command db_show_cmds[] = { 400 { "all", 0, 0, db_show_all_cmds }, 401 { "registers", db_show_regs, 0, 0 }, 402 { "breaks", db_listbreak_cmd, 0, 0 }, 403 { "watches", db_listwatch_cmd, 0, 0 }, 404 { "map", db_map_print_cmd, 0, 0 }, 405 { "object", db_object_print_cmd, 0, 0 }, 406 { (char *)0, } 407 }; 408 409 extern void db_print_cmd(), db_examine_cmd(), db_set_cmd(); 410 extern void db_search_cmd(); 411 extern void db_write_cmd(); 412 extern void db_delete_cmd(), db_breakpoint_cmd(); 413 extern void db_deletewatch_cmd(), db_watchpoint_cmd(); 414 extern void db_single_step_cmd(), db_trace_until_call_cmd(), 415 db_trace_until_matching_cmd(), db_continue_cmd(); 416 extern void db_stack_trace_cmd(); 417 void db_help_cmd(); 418 void db_fncall(); 419 420 struct command db_command_table[] = { 421 { "print", db_print_cmd, 0, 0 }, 422 { "examine", db_examine_cmd, CS_SET_DOT, 0 }, 423 { "x", db_examine_cmd, CS_SET_DOT, 0 }, 424 { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, 425 { "set", db_set_cmd, CS_OWN, 0 }, 426 { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 427 { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 428 { "delete", db_delete_cmd, 0, 0 }, 429 { "d", db_delete_cmd, 0, 0 }, 430 { "break", db_breakpoint_cmd, 0, 0 }, 431 { "dwatch", db_deletewatch_cmd, 0, 0 }, 432 { "watch", db_watchpoint_cmd, CS_MORE,0 }, 433 { "step", db_single_step_cmd, 0, 0 }, 434 { "s", db_single_step_cmd, 0, 0 }, 435 { "continue", db_continue_cmd, 0, 0 }, 436 { "c", db_continue_cmd, 0, 0 }, 437 { "until", db_trace_until_call_cmd,0, 0 }, 438 { "next", db_trace_until_matching_cmd,0, 0 }, 439 { "match", db_trace_until_matching_cmd,0, 0 }, 440 { "trace", db_stack_trace_cmd, 0, 0 }, 441 { "call", db_fncall, CS_OWN, 0 }, 442 { "ps", db_show_all_procs, 0, 0 }, 443 { "show", 0, 0, db_show_cmds }, 444 { (char *)0, } 445 }; 446 447 struct command *db_last_command = 0; 448 449 void 450 db_help_cmd() 451 { 452 struct command *cmd = db_command_table; 453 454 while (cmd->name != 0) { 455 db_printf("%-12s", cmd->name); 456 db_end_line(); 457 cmd++; 458 } 459 } 460 461 void 462 db_command_loop() 463 { 464 extern int db_output_line; 465 466 /* 467 * Initialize 'prev' and 'next' to dot. 468 */ 469 db_prev = db_dot; 470 db_next = db_dot; 471 472 db_cmd_loop_done = 0; 473 while (!db_cmd_loop_done) { 474 475 (void) setjmp(db_jmpbuf); 476 if (db_print_position() != 0) 477 db_printf("\n"); 478 db_output_line = 0; 479 480 db_printf("db> "); 481 (void) db_read_line(); 482 483 db_command(&db_last_command, db_command_table); 484 } 485 } 486 487 void 488 db_error(s) 489 char *s; 490 { 491 if (s) 492 db_printf(s); 493 db_flush_lex(); 494 longjmp(db_jmpbuf, 1); 495 } 496 497 498 /* 499 * Call random function: 500 * !expr(arg,arg,arg) 501 */ 502 void 503 db_fncall() 504 { 505 db_expr_t fn_addr; 506 #define MAXARGS 11 507 db_expr_t args[MAXARGS]; 508 int nargs = 0; 509 db_expr_t retval; 510 db_expr_t (*func)(); 511 int t; 512 513 if (!db_expression(&fn_addr)) { 514 db_printf("Bad function\n"); 515 db_flush_lex(); 516 return; 517 } 518 func = (db_expr_t (*) ()) fn_addr; 519 520 t = db_read_token(); 521 if (t == tLPAREN) { 522 if (db_expression(&args[0])) { 523 nargs++; 524 while ((t = db_read_token()) == tCOMMA) { 525 if (nargs == MAXARGS) { 526 db_printf("Too many arguments\n"); 527 db_flush_lex(); 528 return; 529 } 530 if (!db_expression(&args[nargs])) { 531 db_printf("Argument missing\n"); 532 db_flush_lex(); 533 return; 534 } 535 nargs++; 536 } 537 db_unread_token(t); 538 } 539 if (db_read_token() != tRPAREN) { 540 db_printf("?\n"); 541 db_flush_lex(); 542 return; 543 } 544 } 545 db_skip_to_eol(); 546 547 while (nargs < MAXARGS) { 548 args[nargs++] = 0; 549 } 550 551 retval = (*func)(args[0], args[1], args[2], args[3], args[4], 552 args[5], args[6], args[7], args[8], args[9] ); 553 db_printf("%#n\n", retval); 554 } 555