db_command.c revision 12734
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 * 2612734Sbde * $Id: db_command.c,v 1.17 1995/12/07 12:44:48 davidg 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> 3912734Sbde 4012662Sdg#include <vm/vm.h> 4112662Sdg#include <vm/vm_extern.h> 4212734Sbde 432056Swollman#include <ddb/ddb.h> 4412473Sbde#include <ddb/db_command.h> 454Srgrimes#include <ddb/db_lex.h> 464Srgrimes#include <ddb/db_output.h> 474Srgrimes 484Srgrimes#include <setjmp.h> 494Srgrimes 504Srgrimes/* 514Srgrimes * Exported global variables 524Srgrimes */ 534Srgrimesboolean_t db_cmd_loop_done; 544Srgrimesjmp_buf db_jmpbuf; 554Srgrimesdb_addr_t db_dot; 564Srgrimesdb_addr_t db_last_addr; 574Srgrimesdb_addr_t db_prev; 584Srgrimesdb_addr_t db_next; 594Srgrimes 6012515Sphkstatic db_cmdfcn_t db_fncall; 6112515Sphkstatic db_cmdfcn_t db_panic; 624Srgrimes/* 634Srgrimes * if 'ed' style: 'dot' is set at start of last item printed, 644Srgrimes * and '+' points to next line. 654Srgrimes * Otherwise: 'dot' points to next item, '..' points to last. 664Srgrimes */ 6712515Sphkstatic boolean_t db_ed_style = TRUE; 684Srgrimes 694Srgrimes/* 704Srgrimes * Utility routine - discard tokens through end-of-line. 714Srgrimes */ 724Srgrimesvoid 734Srgrimesdb_skip_to_eol() 744Srgrimes{ 754Srgrimes int t; 764Srgrimes do { 774Srgrimes t = db_read_token(); 784Srgrimes } while (t != tEOL); 794Srgrimes} 804Srgrimes 814Srgrimes/* 824Srgrimes * Command table 834Srgrimes */ 844Srgrimesstruct command { 854Srgrimes char * name; /* command name */ 8612473Sbde db_cmdfcn_t *fcn; /* function to call */ 874Srgrimes int flag; /* extra info: */ 884Srgrimes#define CS_OWN 0x1 /* non-standard syntax */ 894Srgrimes#define CS_MORE 0x2 /* standard syntax, but may have other 904Srgrimes words at end */ 914Srgrimes#define CS_SET_DOT 0x100 /* set dot after command */ 924Srgrimes struct command *more; /* another level of command */ 934Srgrimes}; 944Srgrimes 954Srgrimes/* 964Srgrimes * Results of command search. 974Srgrimes */ 984Srgrimes#define CMD_UNIQUE 0 994Srgrimes#define CMD_FOUND 1 1004Srgrimes#define CMD_NONE 2 1014Srgrimes#define CMD_AMBIGUOUS 3 1024Srgrimes#define CMD_HELP 4 1034Srgrimes 10412515Sphkstatic void db_cmd_list __P((struct command *table)); 10512515Sphkstatic int db_cmd_search __P((char *name, struct command *table, 10612473Sbde struct command **cmdp)); 10712515Sphkstatic void db_command __P((struct command **last_cmdp, 10812473Sbde struct command *cmd_table)); 10912473Sbde 1104Srgrimes/* 1114Srgrimes * Search for command prefix. 1124Srgrimes */ 11312515Sphkstatic int 1144Srgrimesdb_cmd_search(name, table, cmdp) 1154Srgrimes char * name; 1164Srgrimes struct command *table; 1174Srgrimes struct command **cmdp; /* out */ 1184Srgrimes{ 1194Srgrimes struct command *cmd; 1204Srgrimes int result = CMD_NONE; 1214Srgrimes 1224Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 1234Srgrimes register char *lp; 1244Srgrimes register char *rp; 1254Srgrimes register int c; 1264Srgrimes 1274Srgrimes lp = name; 1284Srgrimes rp = cmd->name; 1294Srgrimes while ((c = *lp) == *rp) { 1304Srgrimes if (c == 0) { 1314Srgrimes /* complete match */ 1324Srgrimes *cmdp = cmd; 1334Srgrimes return (CMD_UNIQUE); 1344Srgrimes } 1354Srgrimes lp++; 1364Srgrimes rp++; 1374Srgrimes } 1384Srgrimes if (c == 0) { 1394Srgrimes /* end of name, not end of command - 1404Srgrimes partial match */ 1414Srgrimes if (result == CMD_FOUND) { 1424Srgrimes result = CMD_AMBIGUOUS; 1434Srgrimes /* but keep looking for a full match - 1444Srgrimes this lets us match single letters */ 1454Srgrimes } 1464Srgrimes else { 1474Srgrimes *cmdp = cmd; 1484Srgrimes result = CMD_FOUND; 1494Srgrimes } 1504Srgrimes } 1514Srgrimes } 1524Srgrimes if (result == CMD_NONE) { 1534Srgrimes /* check for 'help' */ 1544Srgrimes if (name[0] == 'h' && name[1] == 'e' 1554Srgrimes && name[2] == 'l' && name[3] == 'p') 1564Srgrimes result = CMD_HELP; 1574Srgrimes } 1584Srgrimes return (result); 1594Srgrimes} 1604Srgrimes 16112515Sphkstatic void 1624Srgrimesdb_cmd_list(table) 1634Srgrimes struct command *table; 1644Srgrimes{ 1654Srgrimes register struct command *cmd; 1664Srgrimes 1674Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 1684Srgrimes db_printf("%-12s", cmd->name); 1694Srgrimes db_end_line(); 1704Srgrimes } 1714Srgrimes} 1724Srgrimes 17312515Sphkstatic void 1744Srgrimesdb_command(last_cmdp, cmd_table) 1754Srgrimes struct command **last_cmdp; /* IN_OUT */ 1764Srgrimes struct command *cmd_table; 1774Srgrimes{ 1784Srgrimes struct command *cmd; 1794Srgrimes int t; 1804Srgrimes char modif[TOK_STRING_SIZE]; 1814Srgrimes db_expr_t addr, count; 182798Swollman boolean_t have_addr = FALSE; 1834Srgrimes int result; 1844Srgrimes 1854Srgrimes t = db_read_token(); 1864Srgrimes if (t == tEOL) { 1874Srgrimes /* empty line repeats last command, at 'next' */ 1884Srgrimes cmd = *last_cmdp; 1894Srgrimes addr = (db_expr_t)db_next; 1904Srgrimes have_addr = FALSE; 1914Srgrimes count = 1; 1924Srgrimes modif[0] = '\0'; 1934Srgrimes } 1944Srgrimes else if (t == tEXCL) { 19510348Sbde db_fncall((db_expr_t)0, (boolean_t)0, (db_expr_t)0, (char *)0); 1964Srgrimes return; 1974Srgrimes } 1984Srgrimes else if (t != tIDENT) { 1994Srgrimes db_printf("?\n"); 2004Srgrimes db_flush_lex(); 2014Srgrimes return; 2024Srgrimes } 2034Srgrimes else { 2044Srgrimes /* 2054Srgrimes * Search for command 2064Srgrimes */ 2074Srgrimes while (cmd_table) { 2084Srgrimes result = db_cmd_search(db_tok_string, 2094Srgrimes cmd_table, 2104Srgrimes &cmd); 2114Srgrimes switch (result) { 2124Srgrimes case CMD_NONE: 2134Srgrimes db_printf("No such command\n"); 2144Srgrimes db_flush_lex(); 2154Srgrimes return; 2164Srgrimes case CMD_AMBIGUOUS: 2174Srgrimes db_printf("Ambiguous\n"); 2184Srgrimes db_flush_lex(); 2194Srgrimes return; 2204Srgrimes case CMD_HELP: 2214Srgrimes db_cmd_list(cmd_table); 2224Srgrimes db_flush_lex(); 2234Srgrimes return; 2244Srgrimes default: 2254Srgrimes break; 2264Srgrimes } 2274Srgrimes if ((cmd_table = cmd->more) != 0) { 2284Srgrimes t = db_read_token(); 2294Srgrimes if (t != tIDENT) { 2304Srgrimes db_cmd_list(cmd_table); 2314Srgrimes db_flush_lex(); 2324Srgrimes return; 2334Srgrimes } 2344Srgrimes } 2354Srgrimes } 2364Srgrimes 2374Srgrimes if ((cmd->flag & CS_OWN) == 0) { 2384Srgrimes /* 2394Srgrimes * Standard syntax: 2404Srgrimes * command [/modifier] [addr] [,count] 2414Srgrimes */ 2424Srgrimes t = db_read_token(); 2434Srgrimes if (t == tSLASH) { 2444Srgrimes t = db_read_token(); 2454Srgrimes if (t != tIDENT) { 2464Srgrimes db_printf("Bad modifier\n"); 2474Srgrimes db_flush_lex(); 2484Srgrimes return; 2494Srgrimes } 2504Srgrimes db_strcpy(modif, db_tok_string); 2514Srgrimes } 2524Srgrimes else { 2534Srgrimes db_unread_token(t); 2544Srgrimes modif[0] = '\0'; 2554Srgrimes } 2564Srgrimes 2574Srgrimes if (db_expression(&addr)) { 2584Srgrimes db_dot = (db_addr_t) addr; 2594Srgrimes db_last_addr = db_dot; 2604Srgrimes have_addr = TRUE; 2614Srgrimes } 2624Srgrimes else { 2634Srgrimes addr = (db_expr_t) db_dot; 2644Srgrimes have_addr = FALSE; 2654Srgrimes } 2664Srgrimes t = db_read_token(); 2674Srgrimes if (t == tCOMMA) { 2684Srgrimes if (!db_expression(&count)) { 2694Srgrimes db_printf("Count missing\n"); 2704Srgrimes db_flush_lex(); 2714Srgrimes return; 2724Srgrimes } 2734Srgrimes } 2744Srgrimes else { 2754Srgrimes db_unread_token(t); 2764Srgrimes count = -1; 2774Srgrimes } 2784Srgrimes if ((cmd->flag & CS_MORE) == 0) { 2794Srgrimes db_skip_to_eol(); 2804Srgrimes } 2814Srgrimes } 2824Srgrimes } 2834Srgrimes *last_cmdp = cmd; 2844Srgrimes if (cmd != 0) { 2854Srgrimes /* 2864Srgrimes * Execute the command. 2874Srgrimes */ 2884Srgrimes (*cmd->fcn)(addr, have_addr, count, modif); 2894Srgrimes 2904Srgrimes if (cmd->flag & CS_SET_DOT) { 2914Srgrimes /* 2924Srgrimes * If command changes dot, set dot to 2934Srgrimes * previous address displayed (if 'ed' style). 2944Srgrimes */ 2954Srgrimes if (db_ed_style) { 2964Srgrimes db_dot = db_prev; 2974Srgrimes } 2984Srgrimes else { 2994Srgrimes db_dot = db_next; 3004Srgrimes } 3014Srgrimes } 3024Srgrimes else { 3034Srgrimes /* 3044Srgrimes * If command does not change dot, 3054Srgrimes * set 'next' location to be the same. 3064Srgrimes */ 3074Srgrimes db_next = db_dot; 3084Srgrimes } 3094Srgrimes } 3104Srgrimes} 3114Srgrimes 3124Srgrimes/* 3134Srgrimes * 'show' commands 3144Srgrimes */ 3152112Swollman 31612515Sphkstatic struct command db_show_all_cmds[] = { 3174Srgrimes#if 0 3181147Sguido { "threads", db_show_all_threads, 0, 0 }, 3192320Sdg#endif 3201549Srgrimes { "procs", db_ps, 0, 0 }, 3214Srgrimes { (char *)0 } 3224Srgrimes}; 3234Srgrimes 32412515Sphkstatic struct command db_show_cmds[] = { 3254Srgrimes { "all", 0, 0, db_show_all_cmds }, 3264Srgrimes { "registers", db_show_regs, 0, 0 }, 3274Srgrimes { "breaks", db_listbreak_cmd, 0, 0 }, 3284Srgrimes { "watches", db_listwatch_cmd, 0, 0 }, 3294Srgrimes#if 0 3304Srgrimes { "thread", db_show_one_thread, 0, 0 }, 3314Srgrimes#endif 3324Srgrimes { "map", vm_map_print, 0, 0 }, 3334Srgrimes { "object", vm_object_print, 0, 0 }, 3344Srgrimes#if 0 3354Srgrimes { "page", vm_page_print, 0, 0 }, 3364Srgrimes#endif 3374Srgrimes#if 0 3384Srgrimes { "port", ipc_port_print, 0, 0 }, 3394Srgrimes#endif 3404Srgrimes { (char *)0, } 3414Srgrimes}; 3424Srgrimes 34312515Sphkstatic struct command db_command_table[] = { 3444Srgrimes { "print", db_print_cmd, 0, 0 }, 3456920Sjoerg { "p", db_print_cmd, 0, 0 }, 3464Srgrimes { "examine", db_examine_cmd, CS_SET_DOT, 0 }, 3474Srgrimes { "x", db_examine_cmd, CS_SET_DOT, 0 }, 3484Srgrimes { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, 3494Srgrimes { "set", db_set_cmd, CS_OWN, 0 }, 3504Srgrimes { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 3514Srgrimes { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 3524Srgrimes { "delete", db_delete_cmd, 0, 0 }, 3534Srgrimes { "d", db_delete_cmd, 0, 0 }, 3544Srgrimes { "break", db_breakpoint_cmd, 0, 0 }, 3554Srgrimes { "dwatch", db_deletewatch_cmd, 0, 0 }, 3564Srgrimes { "watch", db_watchpoint_cmd, CS_MORE,0 }, 3574Srgrimes { "step", db_single_step_cmd, 0, 0 }, 3584Srgrimes { "s", db_single_step_cmd, 0, 0 }, 3594Srgrimes { "continue", db_continue_cmd, 0, 0 }, 3604Srgrimes { "c", db_continue_cmd, 0, 0 }, 3614Srgrimes { "until", db_trace_until_call_cmd,0, 0 }, 3624Srgrimes { "next", db_trace_until_matching_cmd,0, 0 }, 3634Srgrimes { "match", db_trace_until_matching_cmd,0, 0 }, 3644Srgrimes { "trace", db_stack_trace_cmd, 0, 0 }, 3654Srgrimes { "call", db_fncall, CS_OWN, 0 }, 3664Srgrimes { "show", 0, 0, db_show_cmds }, 3671147Sguido { "ps", db_ps, 0, 0 }, 3686204Sphk { "panic", db_panic, 0, 0 }, 3694Srgrimes { (char *)0, } 3704Srgrimes}; 3714Srgrimes 37212515Sphkstatic struct command *db_last_command = 0; 3734Srgrimes 3747090Sbde#if 0 3754Srgrimesvoid 3764Srgrimesdb_help_cmd() 3774Srgrimes{ 3784Srgrimes struct command *cmd = db_command_table; 3794Srgrimes 3804Srgrimes while (cmd->name != 0) { 3814Srgrimes db_printf("%-12s", cmd->name); 3824Srgrimes db_end_line(); 3834Srgrimes cmd++; 3844Srgrimes } 3854Srgrimes} 3867090Sbde#endif 3874Srgrimes 38812515Sphkstatic void 38910348Sbdedb_panic(dummy1, dummy2, dummy3, dummy4) 39010348Sbde db_expr_t dummy1; 39110348Sbde boolean_t dummy2; 39210348Sbde db_expr_t dummy3; 39310348Sbde char * dummy4; 3946204Sphk{ 3957170Sdg panic("from debugger"); 3966204Sphk} 3976204Sphk 3986204Sphkvoid 3994Srgrimesdb_command_loop() 4004Srgrimes{ 4014Srgrimes /* 4024Srgrimes * Initialize 'prev' and 'next' to dot. 4034Srgrimes */ 4044Srgrimes db_prev = db_dot; 4054Srgrimes db_next = db_dot; 4064Srgrimes 4074Srgrimes db_cmd_loop_done = 0; 4084Srgrimes while (!db_cmd_loop_done) { 4094Srgrimes 4104Srgrimes (void) setjmp(db_jmpbuf); 4114Srgrimes if (db_print_position() != 0) 4124Srgrimes db_printf("\n"); 4134Srgrimes 4144Srgrimes db_printf("db> "); 4154Srgrimes (void) db_read_line(); 4164Srgrimes 4174Srgrimes db_command(&db_last_command, db_command_table); 4184Srgrimes } 4194Srgrimes} 4204Srgrimes 4214Srgrimesvoid 4224Srgrimesdb_error(s) 4234Srgrimes char *s; 4244Srgrimes{ 4254Srgrimes if (s) 4264Srgrimes db_printf(s); 4274Srgrimes db_flush_lex(); 4284Srgrimes longjmp(db_jmpbuf, 1); 4294Srgrimes} 4304Srgrimes 4314Srgrimes 4324Srgrimes/* 4334Srgrimes * Call random function: 4344Srgrimes * !expr(arg,arg,arg) 4354Srgrimes */ 43612515Sphkstatic void 43710348Sbdedb_fncall(dummy1, dummy2, dummy3, dummy4) 43810348Sbde db_expr_t dummy1; 43910348Sbde boolean_t dummy2; 44010348Sbde db_expr_t dummy3; 44110348Sbde char * dummy4; 4424Srgrimes{ 4434Srgrimes db_expr_t fn_addr; 44412473Sbde#define MAXARGS 11 /* XXX only 10 are passed */ 4454Srgrimes db_expr_t args[MAXARGS]; 4464Srgrimes int nargs = 0; 4474Srgrimes db_expr_t retval; 44812473Sbde typedef db_expr_t fcn_10args_t __P((db_expr_t, db_expr_t, db_expr_t, 44912473Sbde db_expr_t, db_expr_t, db_expr_t, 45012473Sbde db_expr_t, db_expr_t, db_expr_t, 45112473Sbde db_expr_t)); 45212473Sbde fcn_10args_t *func; 4534Srgrimes int t; 4544Srgrimes 4554Srgrimes if (!db_expression(&fn_addr)) { 4564Srgrimes db_printf("Bad function\n"); 4574Srgrimes db_flush_lex(); 4584Srgrimes return; 4594Srgrimes } 46012473Sbde func = (fcn_10args_t *)fn_addr; /* XXX */ 4614Srgrimes 4624Srgrimes t = db_read_token(); 4634Srgrimes if (t == tLPAREN) { 4644Srgrimes if (db_expression(&args[0])) { 4654Srgrimes nargs++; 4664Srgrimes while ((t = db_read_token()) == tCOMMA) { 4674Srgrimes if (nargs == MAXARGS) { 4684Srgrimes db_printf("Too many arguments\n"); 4694Srgrimes db_flush_lex(); 4704Srgrimes return; 4714Srgrimes } 4724Srgrimes if (!db_expression(&args[nargs])) { 4734Srgrimes db_printf("Argument missing\n"); 4744Srgrimes db_flush_lex(); 4754Srgrimes return; 4764Srgrimes } 4774Srgrimes nargs++; 4784Srgrimes } 4794Srgrimes db_unread_token(t); 4804Srgrimes } 4814Srgrimes if (db_read_token() != tRPAREN) { 4824Srgrimes db_printf("?\n"); 4834Srgrimes db_flush_lex(); 4844Srgrimes return; 4854Srgrimes } 4864Srgrimes } 4874Srgrimes db_skip_to_eol(); 4884Srgrimes 4894Srgrimes while (nargs < MAXARGS) { 4904Srgrimes args[nargs++] = 0; 4914Srgrimes } 4924Srgrimes 4934Srgrimes retval = (*func)(args[0], args[1], args[2], args[3], args[4], 4944Srgrimes args[5], args[6], args[7], args[8], args[9] ); 4954Srgrimes db_printf("%#n\n", retval); 4964Srgrimes} 497