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 * $Id: db_command.c,v 1.3 1993/05/20 03:39:10 cgd Exp $ 28 * 29 * HISTORY 30 * $Log: 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 /* 352 * 'show' commands 353 */ 354 extern void db_listbreak_cmd(); 355 extern void db_listwatch_cmd(); 356 extern void db_show_regs(), db_show_one_thread(), db_show_all_threads(); 357 extern void vm_map_print(), vm_object_print(), vm_page_print(); 358 extern void ipc_port_print(); 359 void db_show_help(); 360 361 struct command db_show_all_cmds[] = { 362 #if 0 363 { "threads", db_show_all_threads,0, 0 }, 364 #endif 365 { (char *)0 } 366 }; 367 368 struct command db_show_cmds[] = { 369 { "all", 0, 0, db_show_all_cmds }, 370 { "registers", db_show_regs, 0, 0 }, 371 { "breaks", db_listbreak_cmd, 0, 0 }, 372 { "watches", db_listwatch_cmd, 0, 0 }, 373 #if 0 374 { "thread", db_show_one_thread, 0, 0 }, 375 #endif 376 { "map", vm_map_print, 0, 0 }, 377 { "object", vm_object_print, 0, 0 }, 378 #if 0 379 { "page", vm_page_print, 0, 0 }, 380 #endif 381 #if 0 382 { "port", ipc_port_print, 0, 0 }, 383 #endif 384 { (char *)0, } 385 }; 386 387 extern void db_print_cmd(), db_examine_cmd(), db_set_cmd(); 388 extern void db_search_cmd(); 389 extern void db_write_cmd(); 390 extern void db_delete_cmd(), db_breakpoint_cmd(); 391 extern void db_deletewatch_cmd(), db_watchpoint_cmd(); 392 extern void db_single_step_cmd(), db_trace_until_call_cmd(), 393 db_trace_until_matching_cmd(), db_continue_cmd(); 394 extern void db_stack_trace_cmd(); 395 void db_help_cmd(); 396 void db_fncall(); 397 398 struct command db_command_table[] = { 399 { "print", db_print_cmd, 0, 0 }, 400 { "examine", db_examine_cmd, CS_SET_DOT, 0 }, 401 { "x", db_examine_cmd, CS_SET_DOT, 0 }, 402 { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, 403 { "set", db_set_cmd, CS_OWN, 0 }, 404 { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 405 { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 406 { "delete", db_delete_cmd, 0, 0 }, 407 { "d", db_delete_cmd, 0, 0 }, 408 { "break", db_breakpoint_cmd, 0, 0 }, 409 { "dwatch", db_deletewatch_cmd, 0, 0 }, 410 { "watch", db_watchpoint_cmd, CS_MORE,0 }, 411 { "step", db_single_step_cmd, 0, 0 }, 412 { "s", db_single_step_cmd, 0, 0 }, 413 { "continue", db_continue_cmd, 0, 0 }, 414 { "c", db_continue_cmd, 0, 0 }, 415 { "until", db_trace_until_call_cmd,0, 0 }, 416 { "next", db_trace_until_matching_cmd,0, 0 }, 417 { "match", db_trace_until_matching_cmd,0, 0 }, 418 { "trace", db_stack_trace_cmd, 0, 0 }, 419 { "call", db_fncall, CS_OWN, 0 }, 420 { "show", 0, 0, db_show_cmds }, 421 { (char *)0, } 422 }; 423 424 struct command *db_last_command = 0; 425 426 void 427 db_help_cmd() 428 { 429 struct command *cmd = db_command_table; 430 431 while (cmd->name != 0) { 432 db_printf("%-12s", cmd->name); 433 db_end_line(); 434 cmd++; 435 } 436 } 437 438 void 439 db_command_loop() 440 { 441 /* 442 * Initialize 'prev' and 'next' to dot. 443 */ 444 db_prev = db_dot; 445 db_next = db_dot; 446 447 db_cmd_loop_done = 0; 448 while (!db_cmd_loop_done) { 449 450 (void) setjmp(db_jmpbuf); 451 if (db_print_position() != 0) 452 db_printf("\n"); 453 454 db_printf("db> "); 455 (void) db_read_line(); 456 457 db_command(&db_last_command, db_command_table); 458 } 459 } 460 461 void 462 db_error(s) 463 char *s; 464 { 465 if (s) 466 db_printf(s); 467 db_flush_lex(); 468 longjmp(db_jmpbuf, 1); 469 } 470 471 472 /* 473 * Call random function: 474 * !expr(arg,arg,arg) 475 */ 476 void 477 db_fncall() 478 { 479 db_expr_t fn_addr; 480 #define MAXARGS 11 481 db_expr_t args[MAXARGS]; 482 int nargs = 0; 483 db_expr_t retval; 484 db_expr_t (*func)(); 485 int t; 486 487 if (!db_expression(&fn_addr)) { 488 db_printf("Bad function\n"); 489 db_flush_lex(); 490 return; 491 } 492 func = (db_expr_t (*) ()) fn_addr; 493 494 t = db_read_token(); 495 if (t == tLPAREN) { 496 if (db_expression(&args[0])) { 497 nargs++; 498 while ((t = db_read_token()) == tCOMMA) { 499 if (nargs == MAXARGS) { 500 db_printf("Too many arguments\n"); 501 db_flush_lex(); 502 return; 503 } 504 if (!db_expression(&args[nargs])) { 505 db_printf("Argument missing\n"); 506 db_flush_lex(); 507 return; 508 } 509 nargs++; 510 } 511 db_unread_token(t); 512 } 513 if (db_read_token() != tRPAREN) { 514 db_printf("?\n"); 515 db_flush_lex(); 516 return; 517 } 518 } 519 db_skip_to_eol(); 520 521 while (nargs < MAXARGS) { 522 args[nargs++] = 0; 523 } 524 525 retval = (*func)(args[0], args[1], args[2], args[3], args[4], 526 args[5], args[6], args[7], args[8], args[9] ); 527 db_printf("%#n\n", retval); 528 } 529