db_command.c revision 12473
18876Srgrimes/* 24Srgrimes * Mach Operating System 34Srgrimes * Copyright (c) 1991,1990 Carnegie Mellon University 44Srgrimes * All Rights Reserved. 58876Srgrimes * 64Srgrimes * Permission to use, copy, modify and distribute this software and its 74Srgrimes * documentation is hereby granted, provided that both the copyright 84Srgrimes * notice and this permission notice appear in all copies of the 94Srgrimes * software, derivative works or modified versions, and any portions 104Srgrimes * thereof, and that both notices appear in supporting documentation. 118876Srgrimes * 128876Srgrimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 134Srgrimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 144Srgrimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 158876Srgrimes * 164Srgrimes * Carnegie Mellon requests users of this software to return to 178876Srgrimes * 184Srgrimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 194Srgrimes * School of Computer Science 204Srgrimes * Carnegie Mellon University 214Srgrimes * Pittsburgh PA 15213-3890 228876Srgrimes * 234Srgrimes * any improvements or extensions that they make and grant Carnegie the 244Srgrimes * rights to redistribute these changes. 254Srgrimes * 2612473Sbde * $Id: db_command.c,v 1.14 1995/08/27 02:39:39 bde Exp $ 274Srgrimes */ 28623Srgrimes 294Srgrimes/* 304Srgrimes * Author: David B. Golub, Carnegie Mellon University 314Srgrimes * Date: 7/90 324Srgrimes */ 33623Srgrimes 344Srgrimes/* 354Srgrimes * Command dispatcher. 364Srgrimes */ 372056Swollman#include <sys/param.h> 382056Swollman#include <sys/systm.h> 392056Swollman#include <sys/proc.h> 402056Swollman#include <ddb/ddb.h> 414Srgrimes 4212473Sbde#include <ddb/db_command.h> 434Srgrimes#include <ddb/db_lex.h> 444Srgrimes#include <ddb/db_output.h> 454Srgrimes 464Srgrimes#include <setjmp.h> 474Srgrimes 484Srgrimes/* 494Srgrimes * Exported global variables 504Srgrimes */ 514Srgrimesboolean_t db_cmd_loop_done; 524Srgrimesjmp_buf db_jmpbuf; 534Srgrimesdb_addr_t db_dot; 544Srgrimesdb_addr_t db_last_addr; 554Srgrimesdb_addr_t db_prev; 564Srgrimesdb_addr_t db_next; 574Srgrimes 584Srgrimes/* 594Srgrimes * if 'ed' style: 'dot' is set at start of last item printed, 604Srgrimes * and '+' points to next line. 614Srgrimes * Otherwise: 'dot' points to next item, '..' points to last. 624Srgrimes */ 634Srgrimesboolean_t db_ed_style = TRUE; 644Srgrimes 654Srgrimes/* 664Srgrimes * Utility routine - discard tokens through end-of-line. 674Srgrimes */ 684Srgrimesvoid 694Srgrimesdb_skip_to_eol() 704Srgrimes{ 714Srgrimes int t; 724Srgrimes do { 734Srgrimes t = db_read_token(); 744Srgrimes } while (t != tEOL); 754Srgrimes} 764Srgrimes 774Srgrimes/* 784Srgrimes * Command table 794Srgrimes */ 804Srgrimesstruct command { 814Srgrimes char * name; /* command name */ 8212473Sbde db_cmdfcn_t *fcn; /* function to call */ 834Srgrimes int flag; /* extra info: */ 844Srgrimes#define CS_OWN 0x1 /* non-standard syntax */ 854Srgrimes#define CS_MORE 0x2 /* standard syntax, but may have other 864Srgrimes words at end */ 874Srgrimes#define CS_SET_DOT 0x100 /* set dot after command */ 884Srgrimes struct command *more; /* another level of command */ 894Srgrimes}; 904Srgrimes 914Srgrimes/* 924Srgrimes * Results of command search. 934Srgrimes */ 944Srgrimes#define CMD_UNIQUE 0 954Srgrimes#define CMD_FOUND 1 964Srgrimes#define CMD_NONE 2 974Srgrimes#define CMD_AMBIGUOUS 3 984Srgrimes#define CMD_HELP 4 994Srgrimes 10012473Sbdeextern void db_cmd_list __P((struct command *table)); 10112473Sbdeextern int db_cmd_search __P((char *name, struct command *table, 10212473Sbde struct command **cmdp)); 10312473Sbdeextern void db_command __P((struct command **last_cmdp, 10412473Sbde struct command *cmd_table)); 10512473Sbde 1064Srgrimes/* 1074Srgrimes * Search for command prefix. 1084Srgrimes */ 1094Srgrimesint 1104Srgrimesdb_cmd_search(name, table, cmdp) 1114Srgrimes char * name; 1124Srgrimes struct command *table; 1134Srgrimes struct command **cmdp; /* out */ 1144Srgrimes{ 1154Srgrimes struct command *cmd; 1164Srgrimes int result = CMD_NONE; 1174Srgrimes 1184Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 1194Srgrimes register char *lp; 1204Srgrimes register char *rp; 1214Srgrimes register int c; 1224Srgrimes 1234Srgrimes lp = name; 1244Srgrimes rp = cmd->name; 1254Srgrimes while ((c = *lp) == *rp) { 1264Srgrimes if (c == 0) { 1274Srgrimes /* complete match */ 1284Srgrimes *cmdp = cmd; 1294Srgrimes return (CMD_UNIQUE); 1304Srgrimes } 1314Srgrimes lp++; 1324Srgrimes rp++; 1334Srgrimes } 1344Srgrimes if (c == 0) { 1354Srgrimes /* end of name, not end of command - 1364Srgrimes partial match */ 1374Srgrimes if (result == CMD_FOUND) { 1384Srgrimes result = CMD_AMBIGUOUS; 1394Srgrimes /* but keep looking for a full match - 1404Srgrimes this lets us match single letters */ 1414Srgrimes } 1424Srgrimes else { 1434Srgrimes *cmdp = cmd; 1444Srgrimes result = CMD_FOUND; 1454Srgrimes } 1464Srgrimes } 1474Srgrimes } 1484Srgrimes if (result == CMD_NONE) { 1494Srgrimes /* check for 'help' */ 1504Srgrimes if (name[0] == 'h' && name[1] == 'e' 1514Srgrimes && name[2] == 'l' && name[3] == 'p') 1524Srgrimes result = CMD_HELP; 1534Srgrimes } 1544Srgrimes return (result); 1554Srgrimes} 1564Srgrimes 1574Srgrimesvoid 1584Srgrimesdb_cmd_list(table) 1594Srgrimes struct command *table; 1604Srgrimes{ 1614Srgrimes register struct command *cmd; 1624Srgrimes 1634Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 1644Srgrimes db_printf("%-12s", cmd->name); 1654Srgrimes db_end_line(); 1664Srgrimes } 1674Srgrimes} 1684Srgrimes 1694Srgrimesvoid 1704Srgrimesdb_command(last_cmdp, cmd_table) 1714Srgrimes struct command **last_cmdp; /* IN_OUT */ 1724Srgrimes struct command *cmd_table; 1734Srgrimes{ 1744Srgrimes struct command *cmd; 1754Srgrimes int t; 1764Srgrimes char modif[TOK_STRING_SIZE]; 1774Srgrimes db_expr_t addr, count; 178798Swollman boolean_t have_addr = FALSE; 1794Srgrimes int result; 1804Srgrimes 1814Srgrimes t = db_read_token(); 1824Srgrimes if (t == tEOL) { 1834Srgrimes /* empty line repeats last command, at 'next' */ 1844Srgrimes cmd = *last_cmdp; 1854Srgrimes addr = (db_expr_t)db_next; 1864Srgrimes have_addr = FALSE; 1874Srgrimes count = 1; 1884Srgrimes modif[0] = '\0'; 1894Srgrimes } 1904Srgrimes else if (t == tEXCL) { 19110348Sbde db_fncall((db_expr_t)0, (boolean_t)0, (db_expr_t)0, (char *)0); 1924Srgrimes return; 1934Srgrimes } 1944Srgrimes else if (t != tIDENT) { 1954Srgrimes db_printf("?\n"); 1964Srgrimes db_flush_lex(); 1974Srgrimes return; 1984Srgrimes } 1994Srgrimes else { 2004Srgrimes /* 2014Srgrimes * Search for command 2024Srgrimes */ 2034Srgrimes while (cmd_table) { 2044Srgrimes result = db_cmd_search(db_tok_string, 2054Srgrimes cmd_table, 2064Srgrimes &cmd); 2074Srgrimes switch (result) { 2084Srgrimes case CMD_NONE: 2094Srgrimes db_printf("No such command\n"); 2104Srgrimes db_flush_lex(); 2114Srgrimes return; 2124Srgrimes case CMD_AMBIGUOUS: 2134Srgrimes db_printf("Ambiguous\n"); 2144Srgrimes db_flush_lex(); 2154Srgrimes return; 2164Srgrimes case CMD_HELP: 2174Srgrimes db_cmd_list(cmd_table); 2184Srgrimes db_flush_lex(); 2194Srgrimes return; 2204Srgrimes default: 2214Srgrimes break; 2224Srgrimes } 2234Srgrimes if ((cmd_table = cmd->more) != 0) { 2244Srgrimes t = db_read_token(); 2254Srgrimes if (t != tIDENT) { 2264Srgrimes db_cmd_list(cmd_table); 2274Srgrimes db_flush_lex(); 2284Srgrimes return; 2294Srgrimes } 2304Srgrimes } 2314Srgrimes } 2324Srgrimes 2334Srgrimes if ((cmd->flag & CS_OWN) == 0) { 2344Srgrimes /* 2354Srgrimes * Standard syntax: 2364Srgrimes * command [/modifier] [addr] [,count] 2374Srgrimes */ 2384Srgrimes t = db_read_token(); 2394Srgrimes if (t == tSLASH) { 2404Srgrimes t = db_read_token(); 2414Srgrimes if (t != tIDENT) { 2424Srgrimes db_printf("Bad modifier\n"); 2434Srgrimes db_flush_lex(); 2444Srgrimes return; 2454Srgrimes } 2464Srgrimes db_strcpy(modif, db_tok_string); 2474Srgrimes } 2484Srgrimes else { 2494Srgrimes db_unread_token(t); 2504Srgrimes modif[0] = '\0'; 2514Srgrimes } 2524Srgrimes 2534Srgrimes if (db_expression(&addr)) { 2544Srgrimes db_dot = (db_addr_t) addr; 2554Srgrimes db_last_addr = db_dot; 2564Srgrimes have_addr = TRUE; 2574Srgrimes } 2584Srgrimes else { 2594Srgrimes addr = (db_expr_t) db_dot; 2604Srgrimes have_addr = FALSE; 2614Srgrimes } 2624Srgrimes t = db_read_token(); 2634Srgrimes if (t == tCOMMA) { 2644Srgrimes if (!db_expression(&count)) { 2654Srgrimes db_printf("Count missing\n"); 2664Srgrimes db_flush_lex(); 2674Srgrimes return; 2684Srgrimes } 2694Srgrimes } 2704Srgrimes else { 2714Srgrimes db_unread_token(t); 2724Srgrimes count = -1; 2734Srgrimes } 2744Srgrimes if ((cmd->flag & CS_MORE) == 0) { 2754Srgrimes db_skip_to_eol(); 2764Srgrimes } 2774Srgrimes } 2784Srgrimes } 2794Srgrimes *last_cmdp = cmd; 2804Srgrimes if (cmd != 0) { 2814Srgrimes /* 2824Srgrimes * Execute the command. 2834Srgrimes */ 2844Srgrimes (*cmd->fcn)(addr, have_addr, count, modif); 2854Srgrimes 2864Srgrimes if (cmd->flag & CS_SET_DOT) { 2874Srgrimes /* 2884Srgrimes * If command changes dot, set dot to 2894Srgrimes * previous address displayed (if 'ed' style). 2904Srgrimes */ 2914Srgrimes if (db_ed_style) { 2924Srgrimes db_dot = db_prev; 2934Srgrimes } 2944Srgrimes else { 2954Srgrimes db_dot = db_next; 2964Srgrimes } 2974Srgrimes } 2984Srgrimes else { 2994Srgrimes /* 3004Srgrimes * If command does not change dot, 3014Srgrimes * set 'next' location to be the same. 3024Srgrimes */ 3034Srgrimes db_next = db_dot; 3044Srgrimes } 3054Srgrimes } 3064Srgrimes} 3074Srgrimes 3084Srgrimes/* 3094Srgrimes * 'show' commands 3104Srgrimes */ 3112112Swollman 3124Srgrimesstruct command db_show_all_cmds[] = { 3134Srgrimes#if 0 3141147Sguido { "threads", db_show_all_threads, 0, 0 }, 3152320Sdg#endif 3161549Srgrimes { "procs", db_ps, 0, 0 }, 3174Srgrimes { (char *)0 } 3184Srgrimes}; 3194Srgrimes 3204Srgrimesstruct command db_show_cmds[] = { 3214Srgrimes { "all", 0, 0, db_show_all_cmds }, 3224Srgrimes { "registers", db_show_regs, 0, 0 }, 3234Srgrimes { "breaks", db_listbreak_cmd, 0, 0 }, 3244Srgrimes { "watches", db_listwatch_cmd, 0, 0 }, 3254Srgrimes#if 0 3264Srgrimes { "thread", db_show_one_thread, 0, 0 }, 3274Srgrimes#endif 3284Srgrimes { "map", vm_map_print, 0, 0 }, 3294Srgrimes { "object", vm_object_print, 0, 0 }, 3304Srgrimes#if 0 3314Srgrimes { "page", vm_page_print, 0, 0 }, 3324Srgrimes#endif 3334Srgrimes#if 0 3344Srgrimes { "port", ipc_port_print, 0, 0 }, 3354Srgrimes#endif 3364Srgrimes { (char *)0, } 3374Srgrimes}; 3384Srgrimes 3394Srgrimesstruct command db_command_table[] = { 3404Srgrimes { "print", db_print_cmd, 0, 0 }, 3416920Sjoerg { "p", db_print_cmd, 0, 0 }, 3424Srgrimes { "examine", db_examine_cmd, CS_SET_DOT, 0 }, 3434Srgrimes { "x", db_examine_cmd, CS_SET_DOT, 0 }, 3444Srgrimes { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, 3454Srgrimes { "set", db_set_cmd, CS_OWN, 0 }, 3464Srgrimes { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 3474Srgrimes { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 3484Srgrimes { "delete", db_delete_cmd, 0, 0 }, 3494Srgrimes { "d", db_delete_cmd, 0, 0 }, 3504Srgrimes { "break", db_breakpoint_cmd, 0, 0 }, 3514Srgrimes { "dwatch", db_deletewatch_cmd, 0, 0 }, 3524Srgrimes { "watch", db_watchpoint_cmd, CS_MORE,0 }, 3534Srgrimes { "step", db_single_step_cmd, 0, 0 }, 3544Srgrimes { "s", db_single_step_cmd, 0, 0 }, 3554Srgrimes { "continue", db_continue_cmd, 0, 0 }, 3564Srgrimes { "c", db_continue_cmd, 0, 0 }, 3574Srgrimes { "until", db_trace_until_call_cmd,0, 0 }, 3584Srgrimes { "next", db_trace_until_matching_cmd,0, 0 }, 3594Srgrimes { "match", db_trace_until_matching_cmd,0, 0 }, 3604Srgrimes { "trace", db_stack_trace_cmd, 0, 0 }, 3614Srgrimes { "call", db_fncall, CS_OWN, 0 }, 3624Srgrimes { "show", 0, 0, db_show_cmds }, 3631147Sguido { "ps", db_ps, 0, 0 }, 3646204Sphk { "panic", db_panic, 0, 0 }, 3654Srgrimes { (char *)0, } 3664Srgrimes}; 3674Srgrimes 3684Srgrimesstruct command *db_last_command = 0; 3694Srgrimes 3707090Sbde#if 0 3714Srgrimesvoid 3724Srgrimesdb_help_cmd() 3734Srgrimes{ 3744Srgrimes struct command *cmd = db_command_table; 3754Srgrimes 3764Srgrimes while (cmd->name != 0) { 3774Srgrimes db_printf("%-12s", cmd->name); 3784Srgrimes db_end_line(); 3794Srgrimes cmd++; 3804Srgrimes } 3814Srgrimes} 3827090Sbde#endif 3834Srgrimes 3844Srgrimesvoid 38510348Sbdedb_panic(dummy1, dummy2, dummy3, dummy4) 38610348Sbde db_expr_t dummy1; 38710348Sbde boolean_t dummy2; 38810348Sbde db_expr_t dummy3; 38910348Sbde char * dummy4; 3906204Sphk{ 3917170Sdg panic("from debugger"); 3926204Sphk} 3936204Sphk 3946204Sphkvoid 3954Srgrimesdb_command_loop() 3964Srgrimes{ 3974Srgrimes /* 3984Srgrimes * Initialize 'prev' and 'next' to dot. 3994Srgrimes */ 4004Srgrimes db_prev = db_dot; 4014Srgrimes db_next = db_dot; 4024Srgrimes 4034Srgrimes db_cmd_loop_done = 0; 4044Srgrimes while (!db_cmd_loop_done) { 4054Srgrimes 4064Srgrimes (void) setjmp(db_jmpbuf); 4074Srgrimes if (db_print_position() != 0) 4084Srgrimes db_printf("\n"); 4094Srgrimes 4104Srgrimes db_printf("db> "); 4114Srgrimes (void) db_read_line(); 4124Srgrimes 4134Srgrimes db_command(&db_last_command, db_command_table); 4144Srgrimes } 4154Srgrimes} 4164Srgrimes 4174Srgrimesvoid 4184Srgrimesdb_error(s) 4194Srgrimes char *s; 4204Srgrimes{ 4214Srgrimes if (s) 4224Srgrimes db_printf(s); 4234Srgrimes db_flush_lex(); 4244Srgrimes longjmp(db_jmpbuf, 1); 4254Srgrimes} 4264Srgrimes 4274Srgrimes 4284Srgrimes/* 4294Srgrimes * Call random function: 4304Srgrimes * !expr(arg,arg,arg) 4314Srgrimes */ 4324Srgrimesvoid 43310348Sbdedb_fncall(dummy1, dummy2, dummy3, dummy4) 43410348Sbde db_expr_t dummy1; 43510348Sbde boolean_t dummy2; 43610348Sbde db_expr_t dummy3; 43710348Sbde char * dummy4; 4384Srgrimes{ 4394Srgrimes db_expr_t fn_addr; 44012473Sbde#define MAXARGS 11 /* XXX only 10 are passed */ 4414Srgrimes db_expr_t args[MAXARGS]; 4424Srgrimes int nargs = 0; 4434Srgrimes db_expr_t retval; 44412473Sbde typedef db_expr_t fcn_10args_t __P((db_expr_t, db_expr_t, db_expr_t, 44512473Sbde db_expr_t, db_expr_t, db_expr_t, 44612473Sbde db_expr_t, db_expr_t, db_expr_t, 44712473Sbde db_expr_t)); 44812473Sbde fcn_10args_t *func; 4494Srgrimes int t; 4504Srgrimes 4514Srgrimes if (!db_expression(&fn_addr)) { 4524Srgrimes db_printf("Bad function\n"); 4534Srgrimes db_flush_lex(); 4544Srgrimes return; 4554Srgrimes } 45612473Sbde func = (fcn_10args_t *)fn_addr; /* XXX */ 4574Srgrimes 4584Srgrimes t = db_read_token(); 4594Srgrimes if (t == tLPAREN) { 4604Srgrimes if (db_expression(&args[0])) { 4614Srgrimes nargs++; 4624Srgrimes while ((t = db_read_token()) == tCOMMA) { 4634Srgrimes if (nargs == MAXARGS) { 4644Srgrimes db_printf("Too many arguments\n"); 4654Srgrimes db_flush_lex(); 4664Srgrimes return; 4674Srgrimes } 4684Srgrimes if (!db_expression(&args[nargs])) { 4694Srgrimes db_printf("Argument missing\n"); 4704Srgrimes db_flush_lex(); 4714Srgrimes return; 4724Srgrimes } 4734Srgrimes nargs++; 4744Srgrimes } 4754Srgrimes db_unread_token(t); 4764Srgrimes } 4774Srgrimes if (db_read_token() != tRPAREN) { 4784Srgrimes db_printf("?\n"); 4794Srgrimes db_flush_lex(); 4804Srgrimes return; 4814Srgrimes } 4824Srgrimes } 4834Srgrimes db_skip_to_eol(); 4844Srgrimes 4854Srgrimes while (nargs < MAXARGS) { 4864Srgrimes args[nargs++] = 0; 4874Srgrimes } 4884Srgrimes 4894Srgrimes retval = (*func)(args[0], args[1], args[2], args[3], args[4], 4904Srgrimes args[5], args[6], args[7], args[8], args[9] ); 4914Srgrimes db_printf("%#n\n", retval); 4924Srgrimes} 493