db_command.c revision 6204
14Srgrimes/* 24Srgrimes * Mach Operating System 34Srgrimes * Copyright (c) 1991,1990 Carnegie Mellon University 44Srgrimes * All Rights Reserved. 54Srgrimes * 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. 114Srgrimes * 124Srgrimes * 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. 154Srgrimes * 164Srgrimes * Carnegie Mellon requests users of this software to return to 174Srgrimes * 184Srgrimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 194Srgrimes * School of Computer Science 204Srgrimes * Carnegie Mellon University 214Srgrimes * Pittsburgh PA 15213-3890 224Srgrimes * 234Srgrimes * any improvements or extensions that they make and grant Carnegie the 244Srgrimes * rights to redistribute these changes. 254Srgrimes * 266204Sphk * $Id: db_command.c,v 1.8 1994/08/27 16:14:08 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> 392056Swollman#include <sys/proc.h> 402056Swollman#include <ddb/ddb.h> 414Srgrimes 424Srgrimes#include <ddb/db_lex.h> 434Srgrimes#include <ddb/db_output.h> 444Srgrimes 454Srgrimes#include <setjmp.h> 464Srgrimes 474Srgrimes/* 484Srgrimes * Exported global variables 494Srgrimes */ 504Srgrimesboolean_t db_cmd_loop_done; 514Srgrimesjmp_buf db_jmpbuf; 524Srgrimesdb_addr_t db_dot; 534Srgrimesdb_addr_t db_last_addr; 544Srgrimesdb_addr_t db_prev; 554Srgrimesdb_addr_t db_next; 564Srgrimes 574Srgrimes/* 584Srgrimes * if 'ed' style: 'dot' is set at start of last item printed, 594Srgrimes * and '+' points to next line. 604Srgrimes * Otherwise: 'dot' points to next item, '..' points to last. 614Srgrimes */ 624Srgrimesboolean_t db_ed_style = TRUE; 634Srgrimes 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 */ 824Srgrimes void (*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 1004Srgrimes/* 1014Srgrimes * Search for command prefix. 1024Srgrimes */ 1034Srgrimesint 1044Srgrimesdb_cmd_search(name, table, cmdp) 1054Srgrimes char * name; 1064Srgrimes struct command *table; 1074Srgrimes struct command **cmdp; /* out */ 1084Srgrimes{ 1094Srgrimes struct command *cmd; 1104Srgrimes int result = CMD_NONE; 1114Srgrimes 1124Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 1134Srgrimes register char *lp; 1144Srgrimes register char *rp; 1154Srgrimes register int c; 1164Srgrimes 1174Srgrimes lp = name; 1184Srgrimes rp = cmd->name; 1194Srgrimes while ((c = *lp) == *rp) { 1204Srgrimes if (c == 0) { 1214Srgrimes /* complete match */ 1224Srgrimes *cmdp = cmd; 1234Srgrimes return (CMD_UNIQUE); 1244Srgrimes } 1254Srgrimes lp++; 1264Srgrimes rp++; 1274Srgrimes } 1284Srgrimes if (c == 0) { 1294Srgrimes /* end of name, not end of command - 1304Srgrimes partial match */ 1314Srgrimes if (result == CMD_FOUND) { 1324Srgrimes result = CMD_AMBIGUOUS; 1334Srgrimes /* but keep looking for a full match - 1344Srgrimes this lets us match single letters */ 1354Srgrimes } 1364Srgrimes else { 1374Srgrimes *cmdp = cmd; 1384Srgrimes result = CMD_FOUND; 1394Srgrimes } 1404Srgrimes } 1414Srgrimes } 1424Srgrimes if (result == CMD_NONE) { 1434Srgrimes /* check for 'help' */ 1444Srgrimes if (name[0] == 'h' && name[1] == 'e' 1454Srgrimes && name[2] == 'l' && name[3] == 'p') 1464Srgrimes result = CMD_HELP; 1474Srgrimes } 1484Srgrimes return (result); 1494Srgrimes} 1504Srgrimes 1514Srgrimesvoid 1524Srgrimesdb_cmd_list(table) 1534Srgrimes struct command *table; 1544Srgrimes{ 1554Srgrimes register struct command *cmd; 1564Srgrimes 1574Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 1584Srgrimes db_printf("%-12s", cmd->name); 1594Srgrimes db_end_line(); 1604Srgrimes } 1614Srgrimes} 1624Srgrimes 1634Srgrimesvoid 1644Srgrimesdb_command(last_cmdp, cmd_table) 1654Srgrimes struct command **last_cmdp; /* IN_OUT */ 1664Srgrimes struct command *cmd_table; 1674Srgrimes{ 1684Srgrimes struct command *cmd; 1694Srgrimes int t; 1704Srgrimes char modif[TOK_STRING_SIZE]; 1714Srgrimes db_expr_t addr, count; 172798Swollman boolean_t have_addr = FALSE; 1734Srgrimes int result; 1744Srgrimes 1754Srgrimes t = db_read_token(); 1764Srgrimes if (t == tEOL) { 1774Srgrimes /* empty line repeats last command, at 'next' */ 1784Srgrimes cmd = *last_cmdp; 1794Srgrimes addr = (db_expr_t)db_next; 1804Srgrimes have_addr = FALSE; 1814Srgrimes count = 1; 1824Srgrimes modif[0] = '\0'; 1834Srgrimes } 1844Srgrimes else if (t == tEXCL) { 1854Srgrimes void db_fncall(); 1864Srgrimes db_fncall(); 1874Srgrimes return; 1884Srgrimes } 1894Srgrimes else if (t != tIDENT) { 1904Srgrimes db_printf("?\n"); 1914Srgrimes db_flush_lex(); 1924Srgrimes return; 1934Srgrimes } 1944Srgrimes else { 1954Srgrimes /* 1964Srgrimes * Search for command 1974Srgrimes */ 1984Srgrimes while (cmd_table) { 1994Srgrimes result = db_cmd_search(db_tok_string, 2004Srgrimes cmd_table, 2014Srgrimes &cmd); 2024Srgrimes switch (result) { 2034Srgrimes case CMD_NONE: 2044Srgrimes db_printf("No such command\n"); 2054Srgrimes db_flush_lex(); 2064Srgrimes return; 2074Srgrimes case CMD_AMBIGUOUS: 2084Srgrimes db_printf("Ambiguous\n"); 2094Srgrimes db_flush_lex(); 2104Srgrimes return; 2114Srgrimes case CMD_HELP: 2124Srgrimes db_cmd_list(cmd_table); 2134Srgrimes db_flush_lex(); 2144Srgrimes return; 2154Srgrimes default: 2164Srgrimes break; 2174Srgrimes } 2184Srgrimes if ((cmd_table = cmd->more) != 0) { 2194Srgrimes t = db_read_token(); 2204Srgrimes if (t != tIDENT) { 2214Srgrimes db_cmd_list(cmd_table); 2224Srgrimes db_flush_lex(); 2234Srgrimes return; 2244Srgrimes } 2254Srgrimes } 2264Srgrimes } 2274Srgrimes 2284Srgrimes if ((cmd->flag & CS_OWN) == 0) { 2294Srgrimes /* 2304Srgrimes * Standard syntax: 2314Srgrimes * command [/modifier] [addr] [,count] 2324Srgrimes */ 2334Srgrimes t = db_read_token(); 2344Srgrimes if (t == tSLASH) { 2354Srgrimes t = db_read_token(); 2364Srgrimes if (t != tIDENT) { 2374Srgrimes db_printf("Bad modifier\n"); 2384Srgrimes db_flush_lex(); 2394Srgrimes return; 2404Srgrimes } 2414Srgrimes db_strcpy(modif, db_tok_string); 2424Srgrimes } 2434Srgrimes else { 2444Srgrimes db_unread_token(t); 2454Srgrimes modif[0] = '\0'; 2464Srgrimes } 2474Srgrimes 2484Srgrimes if (db_expression(&addr)) { 2494Srgrimes db_dot = (db_addr_t) addr; 2504Srgrimes db_last_addr = db_dot; 2514Srgrimes have_addr = TRUE; 2524Srgrimes } 2534Srgrimes else { 2544Srgrimes addr = (db_expr_t) db_dot; 2554Srgrimes have_addr = FALSE; 2564Srgrimes } 2574Srgrimes t = db_read_token(); 2584Srgrimes if (t == tCOMMA) { 2594Srgrimes if (!db_expression(&count)) { 2604Srgrimes db_printf("Count missing\n"); 2614Srgrimes db_flush_lex(); 2624Srgrimes return; 2634Srgrimes } 2644Srgrimes } 2654Srgrimes else { 2664Srgrimes db_unread_token(t); 2674Srgrimes count = -1; 2684Srgrimes } 2694Srgrimes if ((cmd->flag & CS_MORE) == 0) { 2704Srgrimes db_skip_to_eol(); 2714Srgrimes } 2724Srgrimes } 2734Srgrimes } 2744Srgrimes *last_cmdp = cmd; 2754Srgrimes if (cmd != 0) { 2764Srgrimes /* 2774Srgrimes * Execute the command. 2784Srgrimes */ 2794Srgrimes (*cmd->fcn)(addr, have_addr, count, modif); 2804Srgrimes 2814Srgrimes if (cmd->flag & CS_SET_DOT) { 2824Srgrimes /* 2834Srgrimes * If command changes dot, set dot to 2844Srgrimes * previous address displayed (if 'ed' style). 2854Srgrimes */ 2864Srgrimes if (db_ed_style) { 2874Srgrimes db_dot = db_prev; 2884Srgrimes } 2894Srgrimes else { 2904Srgrimes db_dot = db_next; 2914Srgrimes } 2924Srgrimes } 2934Srgrimes else { 2944Srgrimes /* 2954Srgrimes * If command does not change dot, 2964Srgrimes * set 'next' location to be the same. 2974Srgrimes */ 2984Srgrimes db_next = db_dot; 2994Srgrimes } 3004Srgrimes } 3014Srgrimes} 3024Srgrimes 3034Srgrimes/* 3044Srgrimes * 'show' commands 3054Srgrimes */ 3062112Swollman 3072112Swollmanextern void db_show_one_thread(), db_show_all_threads(); 3082112Swollmanextern void vm_page_print(); 3092320Sdgextern void db_ps(); 3104Srgrimesextern void ipc_port_print(); 3114Srgrimesvoid db_show_help(); 3126204Sphkvoid db_panic(); 3134Srgrimes 3144Srgrimesstruct 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 3224Srgrimesstruct 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 3414Srgrimesvoid db_help_cmd(); 3424Srgrimesvoid db_fncall(); 3434Srgrimes 3444Srgrimesstruct command db_command_table[] = { 3454Srgrimes { "print", 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 3724Srgrimesstruct command *db_last_command = 0; 3734Srgrimes 3744Srgrimesvoid 3754Srgrimesdb_help_cmd() 3764Srgrimes{ 3774Srgrimes struct command *cmd = db_command_table; 3784Srgrimes 3794Srgrimes while (cmd->name != 0) { 3804Srgrimes db_printf("%-12s", cmd->name); 3814Srgrimes db_end_line(); 3824Srgrimes cmd++; 3834Srgrimes } 3844Srgrimes} 3854Srgrimes 3864Srgrimesvoid 3876204Sphkdb_panic() 3886204Sphk{ 3896204Sphk panic("from debugger\n"); 3906204Sphk} 3916204Sphk 3926204Sphkvoid 3934Srgrimesdb_command_loop() 3944Srgrimes{ 3954Srgrimes /* 3964Srgrimes * Initialize 'prev' and 'next' to dot. 3974Srgrimes */ 3984Srgrimes db_prev = db_dot; 3994Srgrimes db_next = db_dot; 4004Srgrimes 4014Srgrimes db_cmd_loop_done = 0; 4024Srgrimes while (!db_cmd_loop_done) { 4034Srgrimes 4044Srgrimes (void) setjmp(db_jmpbuf); 4054Srgrimes if (db_print_position() != 0) 4064Srgrimes db_printf("\n"); 4074Srgrimes 4084Srgrimes db_printf("db> "); 4094Srgrimes (void) db_read_line(); 4104Srgrimes 4114Srgrimes db_command(&db_last_command, db_command_table); 4124Srgrimes } 4134Srgrimes} 4144Srgrimes 4154Srgrimesvoid 4164Srgrimesdb_error(s) 4174Srgrimes char *s; 4184Srgrimes{ 4194Srgrimes if (s) 4204Srgrimes db_printf(s); 4214Srgrimes db_flush_lex(); 4224Srgrimes longjmp(db_jmpbuf, 1); 4234Srgrimes} 4244Srgrimes 4254Srgrimes 4264Srgrimes/* 4274Srgrimes * Call random function: 4284Srgrimes * !expr(arg,arg,arg) 4294Srgrimes */ 4304Srgrimesvoid 4314Srgrimesdb_fncall() 4324Srgrimes{ 4334Srgrimes db_expr_t fn_addr; 4344Srgrimes#define MAXARGS 11 4354Srgrimes db_expr_t args[MAXARGS]; 4364Srgrimes int nargs = 0; 4374Srgrimes db_expr_t retval; 4384Srgrimes db_expr_t (*func)(); 4394Srgrimes int t; 4404Srgrimes 4414Srgrimes if (!db_expression(&fn_addr)) { 4424Srgrimes db_printf("Bad function\n"); 4434Srgrimes db_flush_lex(); 4444Srgrimes return; 4454Srgrimes } 4464Srgrimes func = (db_expr_t (*) ()) fn_addr; 4474Srgrimes 4484Srgrimes t = db_read_token(); 4494Srgrimes if (t == tLPAREN) { 4504Srgrimes if (db_expression(&args[0])) { 4514Srgrimes nargs++; 4524Srgrimes while ((t = db_read_token()) == tCOMMA) { 4534Srgrimes if (nargs == MAXARGS) { 4544Srgrimes db_printf("Too many arguments\n"); 4554Srgrimes db_flush_lex(); 4564Srgrimes return; 4574Srgrimes } 4584Srgrimes if (!db_expression(&args[nargs])) { 4594Srgrimes db_printf("Argument missing\n"); 4604Srgrimes db_flush_lex(); 4614Srgrimes return; 4624Srgrimes } 4634Srgrimes nargs++; 4644Srgrimes } 4654Srgrimes db_unread_token(t); 4664Srgrimes } 4674Srgrimes if (db_read_token() != tRPAREN) { 4684Srgrimes db_printf("?\n"); 4694Srgrimes db_flush_lex(); 4704Srgrimes return; 4714Srgrimes } 4724Srgrimes } 4734Srgrimes db_skip_to_eol(); 4744Srgrimes 4754Srgrimes while (nargs < MAXARGS) { 4764Srgrimes args[nargs++] = 0; 4774Srgrimes } 4784Srgrimes 4794Srgrimes retval = (*func)(args[0], args[1], args[2], args[3], args[4], 4804Srgrimes args[5], args[6], args[7], args[8], args[9] ); 4814Srgrimes db_printf("%#n\n", retval); 4824Srgrimes} 483