db_command.c revision 4
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 */ 264Srgrimes/* 274Srgrimes * HISTORY 284Srgrimes * $Log: db_command.c,v $ 294Srgrimes * 304Srgrimes * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE 314Srgrimes * -------------------- ----- ---------------------- 324Srgrimes * CURRENT PATCH LEVEL: 1 00081 334Srgrimes * -------------------- ----- ---------------------- 344Srgrimes * 354Srgrimes * 01 Feb 93 Julian Elischer move strcmp to a more general 364Srgrimes * part of the kernel. 374Srgrimes * 384Srgrimes * Revision 1.1 1992/03/25 21:45:02 pace 394Srgrimes * Initial revision 404Srgrimes * 414Srgrimes * Revision 2.6 91/02/05 17:06:10 mrt 424Srgrimes * Changed to new Mach copyright 434Srgrimes * [91/01/31 16:17:18 mrt] 444Srgrimes * 454Srgrimes * Revision 2.5 91/01/08 17:31:54 rpd 464Srgrimes * Forward reference for db_fncall(); 474Srgrimes * [91/01/04 12:35:17 rvb] 484Srgrimes * 494Srgrimes * Add call as a synonym for ! and match for next 504Srgrimes * [91/01/04 12:14:48 rvb] 514Srgrimes * 524Srgrimes * Revision 2.4 90/11/07 16:49:15 rpd 534Srgrimes * Added search. 544Srgrimes * [90/11/06 rpd] 554Srgrimes * 564Srgrimes * Revision 2.3 90/10/25 14:43:45 rwd 574Srgrimes * Changed db_fncall to print the result unsigned. 584Srgrimes * [90/10/19 rpd] 594Srgrimes * 604Srgrimes * Added CS_MORE to db_watchpoint_cmd. 614Srgrimes * [90/10/17 rpd] 624Srgrimes * Added watchpoint commands: watch, dwatch, show watches. 634Srgrimes * [90/10/16 rpd] 644Srgrimes * 654Srgrimes * Revision 2.2 90/08/27 21:50:10 dbg 664Srgrimes * Remove 'listbreaks' - use 'show breaks' instead. Change 'show 674Srgrimes * threads' to 'show all threads' to avoid clash with 'show thread'. 684Srgrimes * Set 'dot' here from db_prev or db_next, depending on 'db_ed_style' 694Srgrimes * flag and syntax table. 704Srgrimes * [90/08/22 dbg] 714Srgrimes * Reduce lint. 724Srgrimes * [90/08/07 dbg] 734Srgrimes * Created. 744Srgrimes * [90/07/25 dbg] 754Srgrimes * 764Srgrimes */ 774Srgrimes/* 784Srgrimes * Author: David B. Golub, Carnegie Mellon University 794Srgrimes * Date: 7/90 804Srgrimes */ 814Srgrimes/* 824Srgrimes * Command dispatcher. 834Srgrimes */ 844Srgrimes#include "param.h" 854Srgrimes#include "proc.h" 864Srgrimes#include <machine/db_machdep.h> /* type definitions */ 874Srgrimes 884Srgrimes#include <ddb/db_lex.h> 894Srgrimes#include <ddb/db_output.h> 904Srgrimes 914Srgrimes#include <setjmp.h> 924Srgrimes 934Srgrimes/* 944Srgrimes * Exported global variables 954Srgrimes */ 964Srgrimesboolean_t db_cmd_loop_done; 974Srgrimesjmp_buf db_jmpbuf; 984Srgrimesdb_addr_t db_dot; 994Srgrimesdb_addr_t db_last_addr; 1004Srgrimesdb_addr_t db_prev; 1014Srgrimesdb_addr_t db_next; 1024Srgrimes 1034Srgrimes/* 1044Srgrimes * if 'ed' style: 'dot' is set at start of last item printed, 1054Srgrimes * and '+' points to next line. 1064Srgrimes * Otherwise: 'dot' points to next item, '..' points to last. 1074Srgrimes */ 1084Srgrimesboolean_t db_ed_style = TRUE; 1094Srgrimes 1104Srgrimes 1114Srgrimes/* 1124Srgrimes * Utility routine - discard tokens through end-of-line. 1134Srgrimes */ 1144Srgrimesvoid 1154Srgrimesdb_skip_to_eol() 1164Srgrimes{ 1174Srgrimes int t; 1184Srgrimes do { 1194Srgrimes t = db_read_token(); 1204Srgrimes } while (t != tEOL); 1214Srgrimes} 1224Srgrimes 1234Srgrimes/* 1244Srgrimes * Command table 1254Srgrimes */ 1264Srgrimesstruct command { 1274Srgrimes char * name; /* command name */ 1284Srgrimes void (*fcn)(); /* function to call */ 1294Srgrimes int flag; /* extra info: */ 1304Srgrimes#define CS_OWN 0x1 /* non-standard syntax */ 1314Srgrimes#define CS_MORE 0x2 /* standard syntax, but may have other 1324Srgrimes words at end */ 1334Srgrimes#define CS_SET_DOT 0x100 /* set dot after command */ 1344Srgrimes struct command *more; /* another level of command */ 1354Srgrimes}; 1364Srgrimes 1374Srgrimes/* 1384Srgrimes * Results of command search. 1394Srgrimes */ 1404Srgrimes#define CMD_UNIQUE 0 1414Srgrimes#define CMD_FOUND 1 1424Srgrimes#define CMD_NONE 2 1434Srgrimes#define CMD_AMBIGUOUS 3 1444Srgrimes#define CMD_HELP 4 1454Srgrimes 1464Srgrimes/* 1474Srgrimes * Search for command prefix. 1484Srgrimes */ 1494Srgrimesint 1504Srgrimesdb_cmd_search(name, table, cmdp) 1514Srgrimes char * name; 1524Srgrimes struct command *table; 1534Srgrimes struct command **cmdp; /* out */ 1544Srgrimes{ 1554Srgrimes struct command *cmd; 1564Srgrimes int result = CMD_NONE; 1574Srgrimes 1584Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 1594Srgrimes register char *lp; 1604Srgrimes register char *rp; 1614Srgrimes register int c; 1624Srgrimes 1634Srgrimes lp = name; 1644Srgrimes rp = cmd->name; 1654Srgrimes while ((c = *lp) == *rp) { 1664Srgrimes if (c == 0) { 1674Srgrimes /* complete match */ 1684Srgrimes *cmdp = cmd; 1694Srgrimes return (CMD_UNIQUE); 1704Srgrimes } 1714Srgrimes lp++; 1724Srgrimes rp++; 1734Srgrimes } 1744Srgrimes if (c == 0) { 1754Srgrimes /* end of name, not end of command - 1764Srgrimes partial match */ 1774Srgrimes if (result == CMD_FOUND) { 1784Srgrimes result = CMD_AMBIGUOUS; 1794Srgrimes /* but keep looking for a full match - 1804Srgrimes this lets us match single letters */ 1814Srgrimes } 1824Srgrimes else { 1834Srgrimes *cmdp = cmd; 1844Srgrimes result = CMD_FOUND; 1854Srgrimes } 1864Srgrimes } 1874Srgrimes } 1884Srgrimes if (result == CMD_NONE) { 1894Srgrimes /* check for 'help' */ 1904Srgrimes if (name[0] == 'h' && name[1] == 'e' 1914Srgrimes && name[2] == 'l' && name[3] == 'p') 1924Srgrimes result = CMD_HELP; 1934Srgrimes } 1944Srgrimes return (result); 1954Srgrimes} 1964Srgrimes 1974Srgrimesvoid 1984Srgrimesdb_cmd_list(table) 1994Srgrimes struct command *table; 2004Srgrimes{ 2014Srgrimes register struct command *cmd; 2024Srgrimes 2034Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 2044Srgrimes db_printf("%-12s", cmd->name); 2054Srgrimes db_end_line(); 2064Srgrimes } 2074Srgrimes} 2084Srgrimes 2094Srgrimesvoid 2104Srgrimesdb_command(last_cmdp, cmd_table) 2114Srgrimes struct command **last_cmdp; /* IN_OUT */ 2124Srgrimes struct command *cmd_table; 2134Srgrimes{ 2144Srgrimes struct command *cmd; 2154Srgrimes int t; 2164Srgrimes char modif[TOK_STRING_SIZE]; 2174Srgrimes db_expr_t addr, count; 2184Srgrimes boolean_t have_addr; 2194Srgrimes int result; 2204Srgrimes 2214Srgrimes t = db_read_token(); 2224Srgrimes if (t == tEOL) { 2234Srgrimes /* empty line repeats last command, at 'next' */ 2244Srgrimes cmd = *last_cmdp; 2254Srgrimes addr = (db_expr_t)db_next; 2264Srgrimes have_addr = FALSE; 2274Srgrimes count = 1; 2284Srgrimes modif[0] = '\0'; 2294Srgrimes } 2304Srgrimes else if (t == tEXCL) { 2314Srgrimes void db_fncall(); 2324Srgrimes db_fncall(); 2334Srgrimes return; 2344Srgrimes } 2354Srgrimes else if (t != tIDENT) { 2364Srgrimes db_printf("?\n"); 2374Srgrimes db_flush_lex(); 2384Srgrimes return; 2394Srgrimes } 2404Srgrimes else { 2414Srgrimes /* 2424Srgrimes * Search for command 2434Srgrimes */ 2444Srgrimes while (cmd_table) { 2454Srgrimes result = db_cmd_search(db_tok_string, 2464Srgrimes cmd_table, 2474Srgrimes &cmd); 2484Srgrimes switch (result) { 2494Srgrimes case CMD_NONE: 2504Srgrimes db_printf("No such command\n"); 2514Srgrimes db_flush_lex(); 2524Srgrimes return; 2534Srgrimes case CMD_AMBIGUOUS: 2544Srgrimes db_printf("Ambiguous\n"); 2554Srgrimes db_flush_lex(); 2564Srgrimes return; 2574Srgrimes case CMD_HELP: 2584Srgrimes db_cmd_list(cmd_table); 2594Srgrimes db_flush_lex(); 2604Srgrimes return; 2614Srgrimes default: 2624Srgrimes break; 2634Srgrimes } 2644Srgrimes if ((cmd_table = cmd->more) != 0) { 2654Srgrimes t = db_read_token(); 2664Srgrimes if (t != tIDENT) { 2674Srgrimes db_cmd_list(cmd_table); 2684Srgrimes db_flush_lex(); 2694Srgrimes return; 2704Srgrimes } 2714Srgrimes } 2724Srgrimes } 2734Srgrimes 2744Srgrimes if ((cmd->flag & CS_OWN) == 0) { 2754Srgrimes /* 2764Srgrimes * Standard syntax: 2774Srgrimes * command [/modifier] [addr] [,count] 2784Srgrimes */ 2794Srgrimes t = db_read_token(); 2804Srgrimes if (t == tSLASH) { 2814Srgrimes t = db_read_token(); 2824Srgrimes if (t != tIDENT) { 2834Srgrimes db_printf("Bad modifier\n"); 2844Srgrimes db_flush_lex(); 2854Srgrimes return; 2864Srgrimes } 2874Srgrimes db_strcpy(modif, db_tok_string); 2884Srgrimes } 2894Srgrimes else { 2904Srgrimes db_unread_token(t); 2914Srgrimes modif[0] = '\0'; 2924Srgrimes } 2934Srgrimes 2944Srgrimes if (db_expression(&addr)) { 2954Srgrimes db_dot = (db_addr_t) addr; 2964Srgrimes db_last_addr = db_dot; 2974Srgrimes have_addr = TRUE; 2984Srgrimes } 2994Srgrimes else { 3004Srgrimes addr = (db_expr_t) db_dot; 3014Srgrimes have_addr = FALSE; 3024Srgrimes } 3034Srgrimes t = db_read_token(); 3044Srgrimes if (t == tCOMMA) { 3054Srgrimes if (!db_expression(&count)) { 3064Srgrimes db_printf("Count missing\n"); 3074Srgrimes db_flush_lex(); 3084Srgrimes return; 3094Srgrimes } 3104Srgrimes } 3114Srgrimes else { 3124Srgrimes db_unread_token(t); 3134Srgrimes count = -1; 3144Srgrimes } 3154Srgrimes if ((cmd->flag & CS_MORE) == 0) { 3164Srgrimes db_skip_to_eol(); 3174Srgrimes } 3184Srgrimes } 3194Srgrimes } 3204Srgrimes *last_cmdp = cmd; 3214Srgrimes if (cmd != 0) { 3224Srgrimes /* 3234Srgrimes * Execute the command. 3244Srgrimes */ 3254Srgrimes (*cmd->fcn)(addr, have_addr, count, modif); 3264Srgrimes 3274Srgrimes if (cmd->flag & CS_SET_DOT) { 3284Srgrimes /* 3294Srgrimes * If command changes dot, set dot to 3304Srgrimes * previous address displayed (if 'ed' style). 3314Srgrimes */ 3324Srgrimes if (db_ed_style) { 3334Srgrimes db_dot = db_prev; 3344Srgrimes } 3354Srgrimes else { 3364Srgrimes db_dot = db_next; 3374Srgrimes } 3384Srgrimes } 3394Srgrimes else { 3404Srgrimes /* 3414Srgrimes * If command does not change dot, 3424Srgrimes * set 'next' location to be the same. 3434Srgrimes */ 3444Srgrimes db_next = db_dot; 3454Srgrimes } 3464Srgrimes } 3474Srgrimes} 3484Srgrimes 3494Srgrimes/* 3504Srgrimes * 'show' commands 3514Srgrimes */ 3524Srgrimesextern void db_listbreak_cmd(); 3534Srgrimesextern void db_listwatch_cmd(); 3544Srgrimesextern void db_show_regs(), db_show_one_thread(), db_show_all_threads(); 3554Srgrimesextern void vm_map_print(), vm_object_print(), vm_page_print(); 3564Srgrimesextern void ipc_port_print(); 3574Srgrimesvoid db_show_help(); 3584Srgrimes 3594Srgrimesstruct command db_show_all_cmds[] = { 3604Srgrimes#if 0 3614Srgrimes { "threads", db_show_all_threads,0, 0 }, 3624Srgrimes#endif 3634Srgrimes { (char *)0 } 3644Srgrimes}; 3654Srgrimes 3664Srgrimesstruct command db_show_cmds[] = { 3674Srgrimes { "all", 0, 0, db_show_all_cmds }, 3684Srgrimes { "registers", db_show_regs, 0, 0 }, 3694Srgrimes { "breaks", db_listbreak_cmd, 0, 0 }, 3704Srgrimes { "watches", db_listwatch_cmd, 0, 0 }, 3714Srgrimes#if 0 3724Srgrimes { "thread", db_show_one_thread, 0, 0 }, 3734Srgrimes#endif 3744Srgrimes { "map", vm_map_print, 0, 0 }, 3754Srgrimes { "object", vm_object_print, 0, 0 }, 3764Srgrimes#if 0 3774Srgrimes { "page", vm_page_print, 0, 0 }, 3784Srgrimes#endif 3794Srgrimes#if 0 3804Srgrimes { "port", ipc_port_print, 0, 0 }, 3814Srgrimes#endif 3824Srgrimes { (char *)0, } 3834Srgrimes}; 3844Srgrimes 3854Srgrimesextern void db_print_cmd(), db_examine_cmd(), db_set_cmd(); 3864Srgrimesextern void db_search_cmd(); 3874Srgrimesextern void db_write_cmd(); 3884Srgrimesextern void db_delete_cmd(), db_breakpoint_cmd(); 3894Srgrimesextern void db_deletewatch_cmd(), db_watchpoint_cmd(); 3904Srgrimesextern void db_single_step_cmd(), db_trace_until_call_cmd(), 3914Srgrimes db_trace_until_matching_cmd(), db_continue_cmd(); 3924Srgrimesextern void db_stack_trace_cmd(); 3934Srgrimesvoid db_help_cmd(); 3944Srgrimesvoid db_fncall(); 3954Srgrimes 3964Srgrimesstruct command db_command_table[] = { 3974Srgrimes { "print", db_print_cmd, 0, 0 }, 3984Srgrimes { "examine", db_examine_cmd, CS_SET_DOT, 0 }, 3994Srgrimes { "x", db_examine_cmd, CS_SET_DOT, 0 }, 4004Srgrimes { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, 4014Srgrimes { "set", db_set_cmd, CS_OWN, 0 }, 4024Srgrimes { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 4034Srgrimes { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 4044Srgrimes { "delete", db_delete_cmd, 0, 0 }, 4054Srgrimes { "d", db_delete_cmd, 0, 0 }, 4064Srgrimes { "break", db_breakpoint_cmd, 0, 0 }, 4074Srgrimes { "dwatch", db_deletewatch_cmd, 0, 0 }, 4084Srgrimes { "watch", db_watchpoint_cmd, CS_MORE,0 }, 4094Srgrimes { "step", db_single_step_cmd, 0, 0 }, 4104Srgrimes { "s", db_single_step_cmd, 0, 0 }, 4114Srgrimes { "continue", db_continue_cmd, 0, 0 }, 4124Srgrimes { "c", db_continue_cmd, 0, 0 }, 4134Srgrimes { "until", db_trace_until_call_cmd,0, 0 }, 4144Srgrimes { "next", db_trace_until_matching_cmd,0, 0 }, 4154Srgrimes { "match", db_trace_until_matching_cmd,0, 0 }, 4164Srgrimes { "trace", db_stack_trace_cmd, 0, 0 }, 4174Srgrimes { "call", db_fncall, CS_OWN, 0 }, 4184Srgrimes { "show", 0, 0, db_show_cmds }, 4194Srgrimes { (char *)0, } 4204Srgrimes}; 4214Srgrimes 4224Srgrimesstruct command *db_last_command = 0; 4234Srgrimes 4244Srgrimesvoid 4254Srgrimesdb_help_cmd() 4264Srgrimes{ 4274Srgrimes struct command *cmd = db_command_table; 4284Srgrimes 4294Srgrimes while (cmd->name != 0) { 4304Srgrimes db_printf("%-12s", cmd->name); 4314Srgrimes db_end_line(); 4324Srgrimes cmd++; 4334Srgrimes } 4344Srgrimes} 4354Srgrimes 4364Srgrimesvoid 4374Srgrimesdb_command_loop() 4384Srgrimes{ 4394Srgrimes /* 4404Srgrimes * Initialize 'prev' and 'next' to dot. 4414Srgrimes */ 4424Srgrimes db_prev = db_dot; 4434Srgrimes db_next = db_dot; 4444Srgrimes 4454Srgrimes db_cmd_loop_done = 0; 4464Srgrimes while (!db_cmd_loop_done) { 4474Srgrimes 4484Srgrimes (void) setjmp(db_jmpbuf); 4494Srgrimes if (db_print_position() != 0) 4504Srgrimes db_printf("\n"); 4514Srgrimes 4524Srgrimes db_printf("db> "); 4534Srgrimes (void) db_read_line(); 4544Srgrimes 4554Srgrimes db_command(&db_last_command, db_command_table); 4564Srgrimes } 4574Srgrimes} 4584Srgrimes 4594Srgrimesvoid 4604Srgrimesdb_error(s) 4614Srgrimes char *s; 4624Srgrimes{ 4634Srgrimes if (s) 4644Srgrimes db_printf(s); 4654Srgrimes db_flush_lex(); 4664Srgrimes longjmp(db_jmpbuf, 1); 4674Srgrimes} 4684Srgrimes 4694Srgrimes 4704Srgrimes/* 4714Srgrimes * Call random function: 4724Srgrimes * !expr(arg,arg,arg) 4734Srgrimes */ 4744Srgrimesvoid 4754Srgrimesdb_fncall() 4764Srgrimes{ 4774Srgrimes db_expr_t fn_addr; 4784Srgrimes#define MAXARGS 11 4794Srgrimes db_expr_t args[MAXARGS]; 4804Srgrimes int nargs = 0; 4814Srgrimes db_expr_t retval; 4824Srgrimes db_expr_t (*func)(); 4834Srgrimes int t; 4844Srgrimes 4854Srgrimes if (!db_expression(&fn_addr)) { 4864Srgrimes db_printf("Bad function\n"); 4874Srgrimes db_flush_lex(); 4884Srgrimes return; 4894Srgrimes } 4904Srgrimes func = (db_expr_t (*) ()) fn_addr; 4914Srgrimes 4924Srgrimes t = db_read_token(); 4934Srgrimes if (t == tLPAREN) { 4944Srgrimes if (db_expression(&args[0])) { 4954Srgrimes nargs++; 4964Srgrimes while ((t = db_read_token()) == tCOMMA) { 4974Srgrimes if (nargs == MAXARGS) { 4984Srgrimes db_printf("Too many arguments\n"); 4994Srgrimes db_flush_lex(); 5004Srgrimes return; 5014Srgrimes } 5024Srgrimes if (!db_expression(&args[nargs])) { 5034Srgrimes db_printf("Argument missing\n"); 5044Srgrimes db_flush_lex(); 5054Srgrimes return; 5064Srgrimes } 5074Srgrimes nargs++; 5084Srgrimes } 5094Srgrimes db_unread_token(t); 5104Srgrimes } 5114Srgrimes if (db_read_token() != tRPAREN) { 5124Srgrimes db_printf("?\n"); 5134Srgrimes db_flush_lex(); 5144Srgrimes return; 5154Srgrimes } 5164Srgrimes } 5174Srgrimes db_skip_to_eol(); 5184Srgrimes 5194Srgrimes while (nargs < MAXARGS) { 5204Srgrimes args[nargs++] = 0; 5214Srgrimes } 5224Srgrimes 5234Srgrimes retval = (*func)(args[0], args[1], args[2], args[3], args[4], 5244Srgrimes args[5], args[6], args[7], args[8], args[9] ); 5254Srgrimes db_printf("%#n\n", retval); 5264Srgrimes} 527