db_command.c revision 12515
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 * 2612515Sphk * $Id: db_command.c,v 1.15 1995/11/24 14:13:32 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 5812515Sphkstatic db_cmdfcn_t db_fncall; 5912515Sphkstatic db_cmdfcn_t db_panic; 604Srgrimes/* 614Srgrimes * if 'ed' style: 'dot' is set at start of last item printed, 624Srgrimes * and '+' points to next line. 634Srgrimes * Otherwise: 'dot' points to next item, '..' points to last. 644Srgrimes */ 6512515Sphkstatic boolean_t db_ed_style = TRUE; 664Srgrimes 674Srgrimes/* 684Srgrimes * Utility routine - discard tokens through end-of-line. 694Srgrimes */ 704Srgrimesvoid 714Srgrimesdb_skip_to_eol() 724Srgrimes{ 734Srgrimes int t; 744Srgrimes do { 754Srgrimes t = db_read_token(); 764Srgrimes } while (t != tEOL); 774Srgrimes} 784Srgrimes 794Srgrimes/* 804Srgrimes * Command table 814Srgrimes */ 824Srgrimesstruct command { 834Srgrimes char * name; /* command name */ 8412473Sbde db_cmdfcn_t *fcn; /* function to call */ 854Srgrimes int flag; /* extra info: */ 864Srgrimes#define CS_OWN 0x1 /* non-standard syntax */ 874Srgrimes#define CS_MORE 0x2 /* standard syntax, but may have other 884Srgrimes words at end */ 894Srgrimes#define CS_SET_DOT 0x100 /* set dot after command */ 904Srgrimes struct command *more; /* another level of command */ 914Srgrimes}; 924Srgrimes 934Srgrimes/* 944Srgrimes * Results of command search. 954Srgrimes */ 964Srgrimes#define CMD_UNIQUE 0 974Srgrimes#define CMD_FOUND 1 984Srgrimes#define CMD_NONE 2 994Srgrimes#define CMD_AMBIGUOUS 3 1004Srgrimes#define CMD_HELP 4 1014Srgrimes 10212515Sphkstatic void db_cmd_list __P((struct command *table)); 10312515Sphkstatic int db_cmd_search __P((char *name, struct command *table, 10412473Sbde struct command **cmdp)); 10512515Sphkstatic void db_command __P((struct command **last_cmdp, 10612473Sbde struct command *cmd_table)); 10712473Sbde 1084Srgrimes/* 1094Srgrimes * Search for command prefix. 1104Srgrimes */ 11112515Sphkstatic int 1124Srgrimesdb_cmd_search(name, table, cmdp) 1134Srgrimes char * name; 1144Srgrimes struct command *table; 1154Srgrimes struct command **cmdp; /* out */ 1164Srgrimes{ 1174Srgrimes struct command *cmd; 1184Srgrimes int result = CMD_NONE; 1194Srgrimes 1204Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 1214Srgrimes register char *lp; 1224Srgrimes register char *rp; 1234Srgrimes register int c; 1244Srgrimes 1254Srgrimes lp = name; 1264Srgrimes rp = cmd->name; 1274Srgrimes while ((c = *lp) == *rp) { 1284Srgrimes if (c == 0) { 1294Srgrimes /* complete match */ 1304Srgrimes *cmdp = cmd; 1314Srgrimes return (CMD_UNIQUE); 1324Srgrimes } 1334Srgrimes lp++; 1344Srgrimes rp++; 1354Srgrimes } 1364Srgrimes if (c == 0) { 1374Srgrimes /* end of name, not end of command - 1384Srgrimes partial match */ 1394Srgrimes if (result == CMD_FOUND) { 1404Srgrimes result = CMD_AMBIGUOUS; 1414Srgrimes /* but keep looking for a full match - 1424Srgrimes this lets us match single letters */ 1434Srgrimes } 1444Srgrimes else { 1454Srgrimes *cmdp = cmd; 1464Srgrimes result = CMD_FOUND; 1474Srgrimes } 1484Srgrimes } 1494Srgrimes } 1504Srgrimes if (result == CMD_NONE) { 1514Srgrimes /* check for 'help' */ 1524Srgrimes if (name[0] == 'h' && name[1] == 'e' 1534Srgrimes && name[2] == 'l' && name[3] == 'p') 1544Srgrimes result = CMD_HELP; 1554Srgrimes } 1564Srgrimes return (result); 1574Srgrimes} 1584Srgrimes 15912515Sphkstatic void 1604Srgrimesdb_cmd_list(table) 1614Srgrimes struct command *table; 1624Srgrimes{ 1634Srgrimes register struct command *cmd; 1644Srgrimes 1654Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 1664Srgrimes db_printf("%-12s", cmd->name); 1674Srgrimes db_end_line(); 1684Srgrimes } 1694Srgrimes} 1704Srgrimes 17112515Sphkstatic void 1724Srgrimesdb_command(last_cmdp, cmd_table) 1734Srgrimes struct command **last_cmdp; /* IN_OUT */ 1744Srgrimes struct command *cmd_table; 1754Srgrimes{ 1764Srgrimes struct command *cmd; 1774Srgrimes int t; 1784Srgrimes char modif[TOK_STRING_SIZE]; 1794Srgrimes db_expr_t addr, count; 180798Swollman boolean_t have_addr = FALSE; 1814Srgrimes int result; 1824Srgrimes 1834Srgrimes t = db_read_token(); 1844Srgrimes if (t == tEOL) { 1854Srgrimes /* empty line repeats last command, at 'next' */ 1864Srgrimes cmd = *last_cmdp; 1874Srgrimes addr = (db_expr_t)db_next; 1884Srgrimes have_addr = FALSE; 1894Srgrimes count = 1; 1904Srgrimes modif[0] = '\0'; 1914Srgrimes } 1924Srgrimes else if (t == tEXCL) { 19310348Sbde db_fncall((db_expr_t)0, (boolean_t)0, (db_expr_t)0, (char *)0); 1944Srgrimes return; 1954Srgrimes } 1964Srgrimes else if (t != tIDENT) { 1974Srgrimes db_printf("?\n"); 1984Srgrimes db_flush_lex(); 1994Srgrimes return; 2004Srgrimes } 2014Srgrimes else { 2024Srgrimes /* 2034Srgrimes * Search for command 2044Srgrimes */ 2054Srgrimes while (cmd_table) { 2064Srgrimes result = db_cmd_search(db_tok_string, 2074Srgrimes cmd_table, 2084Srgrimes &cmd); 2094Srgrimes switch (result) { 2104Srgrimes case CMD_NONE: 2114Srgrimes db_printf("No such command\n"); 2124Srgrimes db_flush_lex(); 2134Srgrimes return; 2144Srgrimes case CMD_AMBIGUOUS: 2154Srgrimes db_printf("Ambiguous\n"); 2164Srgrimes db_flush_lex(); 2174Srgrimes return; 2184Srgrimes case CMD_HELP: 2194Srgrimes db_cmd_list(cmd_table); 2204Srgrimes db_flush_lex(); 2214Srgrimes return; 2224Srgrimes default: 2234Srgrimes break; 2244Srgrimes } 2254Srgrimes if ((cmd_table = cmd->more) != 0) { 2264Srgrimes t = db_read_token(); 2274Srgrimes if (t != tIDENT) { 2284Srgrimes db_cmd_list(cmd_table); 2294Srgrimes db_flush_lex(); 2304Srgrimes return; 2314Srgrimes } 2324Srgrimes } 2334Srgrimes } 2344Srgrimes 2354Srgrimes if ((cmd->flag & CS_OWN) == 0) { 2364Srgrimes /* 2374Srgrimes * Standard syntax: 2384Srgrimes * command [/modifier] [addr] [,count] 2394Srgrimes */ 2404Srgrimes t = db_read_token(); 2414Srgrimes if (t == tSLASH) { 2424Srgrimes t = db_read_token(); 2434Srgrimes if (t != tIDENT) { 2444Srgrimes db_printf("Bad modifier\n"); 2454Srgrimes db_flush_lex(); 2464Srgrimes return; 2474Srgrimes } 2484Srgrimes db_strcpy(modif, db_tok_string); 2494Srgrimes } 2504Srgrimes else { 2514Srgrimes db_unread_token(t); 2524Srgrimes modif[0] = '\0'; 2534Srgrimes } 2544Srgrimes 2554Srgrimes if (db_expression(&addr)) { 2564Srgrimes db_dot = (db_addr_t) addr; 2574Srgrimes db_last_addr = db_dot; 2584Srgrimes have_addr = TRUE; 2594Srgrimes } 2604Srgrimes else { 2614Srgrimes addr = (db_expr_t) db_dot; 2624Srgrimes have_addr = FALSE; 2634Srgrimes } 2644Srgrimes t = db_read_token(); 2654Srgrimes if (t == tCOMMA) { 2664Srgrimes if (!db_expression(&count)) { 2674Srgrimes db_printf("Count missing\n"); 2684Srgrimes db_flush_lex(); 2694Srgrimes return; 2704Srgrimes } 2714Srgrimes } 2724Srgrimes else { 2734Srgrimes db_unread_token(t); 2744Srgrimes count = -1; 2754Srgrimes } 2764Srgrimes if ((cmd->flag & CS_MORE) == 0) { 2774Srgrimes db_skip_to_eol(); 2784Srgrimes } 2794Srgrimes } 2804Srgrimes } 2814Srgrimes *last_cmdp = cmd; 2824Srgrimes if (cmd != 0) { 2834Srgrimes /* 2844Srgrimes * Execute the command. 2854Srgrimes */ 2864Srgrimes (*cmd->fcn)(addr, have_addr, count, modif); 2874Srgrimes 2884Srgrimes if (cmd->flag & CS_SET_DOT) { 2894Srgrimes /* 2904Srgrimes * If command changes dot, set dot to 2914Srgrimes * previous address displayed (if 'ed' style). 2924Srgrimes */ 2934Srgrimes if (db_ed_style) { 2944Srgrimes db_dot = db_prev; 2954Srgrimes } 2964Srgrimes else { 2974Srgrimes db_dot = db_next; 2984Srgrimes } 2994Srgrimes } 3004Srgrimes else { 3014Srgrimes /* 3024Srgrimes * If command does not change dot, 3034Srgrimes * set 'next' location to be the same. 3044Srgrimes */ 3054Srgrimes db_next = db_dot; 3064Srgrimes } 3074Srgrimes } 3084Srgrimes} 3094Srgrimes 3104Srgrimes/* 3114Srgrimes * 'show' commands 3124Srgrimes */ 3132112Swollman 31412515Sphkstatic struct command db_show_all_cmds[] = { 3154Srgrimes#if 0 3161147Sguido { "threads", db_show_all_threads, 0, 0 }, 3172320Sdg#endif 3181549Srgrimes { "procs", db_ps, 0, 0 }, 3194Srgrimes { (char *)0 } 3204Srgrimes}; 3214Srgrimes 32212515Sphkstatic struct command db_show_cmds[] = { 3234Srgrimes { "all", 0, 0, db_show_all_cmds }, 3244Srgrimes { "registers", db_show_regs, 0, 0 }, 3254Srgrimes { "breaks", db_listbreak_cmd, 0, 0 }, 3264Srgrimes { "watches", db_listwatch_cmd, 0, 0 }, 3274Srgrimes#if 0 3284Srgrimes { "thread", db_show_one_thread, 0, 0 }, 3294Srgrimes#endif 3304Srgrimes { "map", vm_map_print, 0, 0 }, 3314Srgrimes { "object", vm_object_print, 0, 0 }, 3324Srgrimes#if 0 3334Srgrimes { "page", vm_page_print, 0, 0 }, 3344Srgrimes#endif 3354Srgrimes#if 0 3364Srgrimes { "port", ipc_port_print, 0, 0 }, 3374Srgrimes#endif 3384Srgrimes { (char *)0, } 3394Srgrimes}; 3404Srgrimes 34112515Sphkstatic struct command db_command_table[] = { 3424Srgrimes { "print", db_print_cmd, 0, 0 }, 3436920Sjoerg { "p", db_print_cmd, 0, 0 }, 3444Srgrimes { "examine", db_examine_cmd, CS_SET_DOT, 0 }, 3454Srgrimes { "x", db_examine_cmd, CS_SET_DOT, 0 }, 3464Srgrimes { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, 3474Srgrimes { "set", db_set_cmd, CS_OWN, 0 }, 3484Srgrimes { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 3494Srgrimes { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 3504Srgrimes { "delete", db_delete_cmd, 0, 0 }, 3514Srgrimes { "d", db_delete_cmd, 0, 0 }, 3524Srgrimes { "break", db_breakpoint_cmd, 0, 0 }, 3534Srgrimes { "dwatch", db_deletewatch_cmd, 0, 0 }, 3544Srgrimes { "watch", db_watchpoint_cmd, CS_MORE,0 }, 3554Srgrimes { "step", db_single_step_cmd, 0, 0 }, 3564Srgrimes { "s", db_single_step_cmd, 0, 0 }, 3574Srgrimes { "continue", db_continue_cmd, 0, 0 }, 3584Srgrimes { "c", db_continue_cmd, 0, 0 }, 3594Srgrimes { "until", db_trace_until_call_cmd,0, 0 }, 3604Srgrimes { "next", db_trace_until_matching_cmd,0, 0 }, 3614Srgrimes { "match", db_trace_until_matching_cmd,0, 0 }, 3624Srgrimes { "trace", db_stack_trace_cmd, 0, 0 }, 3634Srgrimes { "call", db_fncall, CS_OWN, 0 }, 3644Srgrimes { "show", 0, 0, db_show_cmds }, 3651147Sguido { "ps", db_ps, 0, 0 }, 3666204Sphk { "panic", db_panic, 0, 0 }, 3674Srgrimes { (char *)0, } 3684Srgrimes}; 3694Srgrimes 37012515Sphkstatic struct command *db_last_command = 0; 3714Srgrimes 3727090Sbde#if 0 3734Srgrimesvoid 3744Srgrimesdb_help_cmd() 3754Srgrimes{ 3764Srgrimes struct command *cmd = db_command_table; 3774Srgrimes 3784Srgrimes while (cmd->name != 0) { 3794Srgrimes db_printf("%-12s", cmd->name); 3804Srgrimes db_end_line(); 3814Srgrimes cmd++; 3824Srgrimes } 3834Srgrimes} 3847090Sbde#endif 3854Srgrimes 38612515Sphkstatic void 38710348Sbdedb_panic(dummy1, dummy2, dummy3, dummy4) 38810348Sbde db_expr_t dummy1; 38910348Sbde boolean_t dummy2; 39010348Sbde db_expr_t dummy3; 39110348Sbde char * dummy4; 3926204Sphk{ 3937170Sdg panic("from debugger"); 3946204Sphk} 3956204Sphk 3966204Sphkvoid 3974Srgrimesdb_command_loop() 3984Srgrimes{ 3994Srgrimes /* 4004Srgrimes * Initialize 'prev' and 'next' to dot. 4014Srgrimes */ 4024Srgrimes db_prev = db_dot; 4034Srgrimes db_next = db_dot; 4044Srgrimes 4054Srgrimes db_cmd_loop_done = 0; 4064Srgrimes while (!db_cmd_loop_done) { 4074Srgrimes 4084Srgrimes (void) setjmp(db_jmpbuf); 4094Srgrimes if (db_print_position() != 0) 4104Srgrimes db_printf("\n"); 4114Srgrimes 4124Srgrimes db_printf("db> "); 4134Srgrimes (void) db_read_line(); 4144Srgrimes 4154Srgrimes db_command(&db_last_command, db_command_table); 4164Srgrimes } 4174Srgrimes} 4184Srgrimes 4194Srgrimesvoid 4204Srgrimesdb_error(s) 4214Srgrimes char *s; 4224Srgrimes{ 4234Srgrimes if (s) 4244Srgrimes db_printf(s); 4254Srgrimes db_flush_lex(); 4264Srgrimes longjmp(db_jmpbuf, 1); 4274Srgrimes} 4284Srgrimes 4294Srgrimes 4304Srgrimes/* 4314Srgrimes * Call random function: 4324Srgrimes * !expr(arg,arg,arg) 4334Srgrimes */ 43412515Sphkstatic void 43510348Sbdedb_fncall(dummy1, dummy2, dummy3, dummy4) 43610348Sbde db_expr_t dummy1; 43710348Sbde boolean_t dummy2; 43810348Sbde db_expr_t dummy3; 43910348Sbde char * dummy4; 4404Srgrimes{ 4414Srgrimes db_expr_t fn_addr; 44212473Sbde#define MAXARGS 11 /* XXX only 10 are passed */ 4434Srgrimes db_expr_t args[MAXARGS]; 4444Srgrimes int nargs = 0; 4454Srgrimes db_expr_t retval; 44612473Sbde typedef db_expr_t fcn_10args_t __P((db_expr_t, db_expr_t, db_expr_t, 44712473Sbde db_expr_t, db_expr_t, db_expr_t, 44812473Sbde db_expr_t, db_expr_t, db_expr_t, 44912473Sbde db_expr_t)); 45012473Sbde fcn_10args_t *func; 4514Srgrimes int t; 4524Srgrimes 4534Srgrimes if (!db_expression(&fn_addr)) { 4544Srgrimes db_printf("Bad function\n"); 4554Srgrimes db_flush_lex(); 4564Srgrimes return; 4574Srgrimes } 45812473Sbde func = (fcn_10args_t *)fn_addr; /* XXX */ 4594Srgrimes 4604Srgrimes t = db_read_token(); 4614Srgrimes if (t == tLPAREN) { 4624Srgrimes if (db_expression(&args[0])) { 4634Srgrimes nargs++; 4644Srgrimes while ((t = db_read_token()) == tCOMMA) { 4654Srgrimes if (nargs == MAXARGS) { 4664Srgrimes db_printf("Too many arguments\n"); 4674Srgrimes db_flush_lex(); 4684Srgrimes return; 4694Srgrimes } 4704Srgrimes if (!db_expression(&args[nargs])) { 4714Srgrimes db_printf("Argument missing\n"); 4724Srgrimes db_flush_lex(); 4734Srgrimes return; 4744Srgrimes } 4754Srgrimes nargs++; 4764Srgrimes } 4774Srgrimes db_unread_token(t); 4784Srgrimes } 4794Srgrimes if (db_read_token() != tRPAREN) { 4804Srgrimes db_printf("?\n"); 4814Srgrimes db_flush_lex(); 4824Srgrimes return; 4834Srgrimes } 4844Srgrimes } 4854Srgrimes db_skip_to_eol(); 4864Srgrimes 4874Srgrimes while (nargs < MAXARGS) { 4884Srgrimes args[nargs++] = 0; 4894Srgrimes } 4904Srgrimes 4914Srgrimes retval = (*func)(args[0], args[1], args[2], args[3], args[4], 4924Srgrimes args[5], args[6], args[7], args[8], args[9] ); 4934Srgrimes db_printf("%#n\n", retval); 4944Srgrimes} 495