db_command.c revision 42654
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 * 2642654Sjdp * $Id: db_command.c,v 1.28 1998/07/08 10:53:45 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> 3842654Sjdp#include <sys/linker_set.h> 3917848Spst#include <sys/reboot.h> 402056Swollman#include <sys/systm.h> 4112734Sbde 422056Swollman#include <ddb/ddb.h> 4312473Sbde#include <ddb/db_command.h> 444Srgrimes#include <ddb/db_lex.h> 454Srgrimes#include <ddb/db_output.h> 464Srgrimes 474Srgrimes#include <setjmp.h> 484Srgrimes 494Srgrimes/* 504Srgrimes * Exported global variables 514Srgrimes */ 524Srgrimesboolean_t db_cmd_loop_done; 5333296Sbdeextern struct linker_set db_cmd_set; 5418296Sbdedb_addr_t db_dot; 554Srgrimesjmp_buf db_jmpbuf; 564Srgrimesdb_addr_t db_last_addr; 574Srgrimesdb_addr_t db_prev; 584Srgrimesdb_addr_t db_next; 5920649Sbdeextern struct linker_set db_show_cmd_set; 604Srgrimes 6112515Sphkstatic db_cmdfcn_t db_fncall; 6217848Spststatic db_cmdfcn_t db_gdb; 6317848Spst 6418296Sbde/* XXX this is actually forward-static. */ 6518296Sbdeextern struct command db_show_cmds[]; 6618296Sbde 674Srgrimes/* 684Srgrimes * if 'ed' style: 'dot' is set at start of last item printed, 694Srgrimes * and '+' points to next line. 704Srgrimes * Otherwise: 'dot' points to next item, '..' points to last. 714Srgrimes */ 7212515Sphkstatic boolean_t db_ed_style = TRUE; 734Srgrimes 744Srgrimes/* 754Srgrimes * Utility routine - discard tokens through end-of-line. 764Srgrimes */ 774Srgrimesvoid 784Srgrimesdb_skip_to_eol() 794Srgrimes{ 804Srgrimes int t; 814Srgrimes do { 824Srgrimes t = db_read_token(); 834Srgrimes } while (t != tEOL); 844Srgrimes} 854Srgrimes 864Srgrimes/* 874Srgrimes * Results of command search. 884Srgrimes */ 894Srgrimes#define CMD_UNIQUE 0 904Srgrimes#define CMD_FOUND 1 914Srgrimes#define CMD_NONE 2 924Srgrimes#define CMD_AMBIGUOUS 3 934Srgrimes#define CMD_HELP 4 944Srgrimes 9518296Sbdestatic void db_cmd_list __P((struct command *table, 9618296Sbde struct command **aux_tablep)); 9712515Sphkstatic int db_cmd_search __P((char *name, struct command *table, 9818296Sbde struct command **aux_tablep, 9912473Sbde struct command **cmdp)); 10012515Sphkstatic void db_command __P((struct command **last_cmdp, 10118296Sbde struct command *cmd_table, 10218296Sbde struct command **aux_cmd_tablep)); 10312473Sbde 1044Srgrimes/* 1054Srgrimes * Search for command prefix. 1064Srgrimes */ 10712515Sphkstatic int 10818296Sbdedb_cmd_search(name, table, aux_tablep, cmdp) 1094Srgrimes char * name; 1104Srgrimes struct command *table; 11118296Sbde struct command **aux_tablep; 1124Srgrimes struct command **cmdp; /* out */ 1134Srgrimes{ 1144Srgrimes struct command *cmd; 11518296Sbde struct command **aux_cmdp; 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 } 14818296Sbde if (result == CMD_NONE && aux_tablep != 0) 14918296Sbde /* XXX repeat too much code. */ 15018296Sbde for (aux_cmdp = aux_tablep; *aux_cmdp != 0; aux_cmdp++) { 15118296Sbde register char *lp; 15218296Sbde register char *rp; 15318296Sbde register int c; 15418296Sbde 15518296Sbde lp = name; 15618296Sbde rp = (*aux_cmdp)->name; 15718296Sbde while ((c = *lp) == *rp) { 15818296Sbde if (c == 0) { 15918296Sbde /* complete match */ 16018296Sbde *cmdp = *aux_cmdp; 16118296Sbde return (CMD_UNIQUE); 16218296Sbde } 16318296Sbde lp++; 16418296Sbde rp++; 16518296Sbde } 16618296Sbde if (c == 0) { 16718296Sbde /* end of name, not end of command - 16818296Sbde partial match */ 16918296Sbde if (result == CMD_FOUND) { 17018296Sbde result = CMD_AMBIGUOUS; 17118296Sbde /* but keep looking for a full match - 17218296Sbde this lets us match single letters */ 17318296Sbde } 17418296Sbde else { 17518296Sbde *cmdp = *aux_cmdp; 17618296Sbde result = CMD_FOUND; 17718296Sbde } 17818296Sbde } 17918296Sbde } 1804Srgrimes if (result == CMD_NONE) { 1814Srgrimes /* check for 'help' */ 1824Srgrimes if (name[0] == 'h' && name[1] == 'e' 1834Srgrimes && name[2] == 'l' && name[3] == 'p') 1844Srgrimes result = CMD_HELP; 1854Srgrimes } 1864Srgrimes return (result); 1874Srgrimes} 1884Srgrimes 18912515Sphkstatic void 19018296Sbdedb_cmd_list(table, aux_tablep) 1914Srgrimes struct command *table; 19218296Sbde struct command **aux_tablep; 1934Srgrimes{ 1944Srgrimes register struct command *cmd; 19518296Sbde register struct command **aux_cmdp; 1964Srgrimes 1974Srgrimes for (cmd = table; cmd->name != 0; cmd++) { 1984Srgrimes db_printf("%-12s", cmd->name); 1994Srgrimes db_end_line(); 2004Srgrimes } 20118296Sbde if (aux_tablep == 0) 20218296Sbde return; 20318296Sbde for (aux_cmdp = aux_tablep; *aux_cmdp != 0; aux_cmdp++) { 20418296Sbde db_printf("%-12s", (*aux_cmdp)->name); 20518296Sbde db_end_line(); 20618296Sbde } 2074Srgrimes} 2084Srgrimes 20912515Sphkstatic void 21018296Sbdedb_command(last_cmdp, cmd_table, aux_cmd_tablep) 2114Srgrimes struct command **last_cmdp; /* IN_OUT */ 2124Srgrimes struct command *cmd_table; 21318296Sbde struct command **aux_cmd_tablep; 2144Srgrimes{ 2154Srgrimes struct command *cmd; 2164Srgrimes int t; 2174Srgrimes char modif[TOK_STRING_SIZE]; 2184Srgrimes db_expr_t addr, count; 219798Swollman boolean_t have_addr = FALSE; 2204Srgrimes int result; 2214Srgrimes 2224Srgrimes t = db_read_token(); 2234Srgrimes if (t == tEOL) { 2244Srgrimes /* empty line repeats last command, at 'next' */ 2254Srgrimes cmd = *last_cmdp; 2264Srgrimes addr = (db_expr_t)db_next; 2274Srgrimes have_addr = FALSE; 2284Srgrimes count = 1; 2294Srgrimes modif[0] = '\0'; 2304Srgrimes } 2314Srgrimes else if (t == tEXCL) { 23210348Sbde db_fncall((db_expr_t)0, (boolean_t)0, (db_expr_t)0, (char *)0); 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, 24718296Sbde aux_cmd_tablep, 2484Srgrimes &cmd); 2494Srgrimes switch (result) { 2504Srgrimes case CMD_NONE: 2514Srgrimes db_printf("No such command\n"); 2524Srgrimes db_flush_lex(); 2534Srgrimes return; 2544Srgrimes case CMD_AMBIGUOUS: 2554Srgrimes db_printf("Ambiguous\n"); 2564Srgrimes db_flush_lex(); 2574Srgrimes return; 2584Srgrimes case CMD_HELP: 25918296Sbde db_cmd_list(cmd_table, aux_cmd_tablep); 2604Srgrimes db_flush_lex(); 2614Srgrimes return; 2624Srgrimes default: 2634Srgrimes break; 2644Srgrimes } 2654Srgrimes if ((cmd_table = cmd->more) != 0) { 26618296Sbde /* XXX usually no more aux's. */ 26718296Sbde aux_cmd_tablep = 0; 26818296Sbde if (cmd_table == db_show_cmds) 26918296Sbde aux_cmd_tablep = 27018296Sbde (struct command **)&db_show_cmd_set.ls_items[0]; 27118296Sbde 2724Srgrimes t = db_read_token(); 2734Srgrimes if (t != tIDENT) { 27418296Sbde db_cmd_list(cmd_table, aux_cmd_tablep); 2754Srgrimes db_flush_lex(); 2764Srgrimes return; 2774Srgrimes } 2784Srgrimes } 2794Srgrimes } 2804Srgrimes 2814Srgrimes if ((cmd->flag & CS_OWN) == 0) { 2824Srgrimes /* 2834Srgrimes * Standard syntax: 2844Srgrimes * command [/modifier] [addr] [,count] 2854Srgrimes */ 2864Srgrimes t = db_read_token(); 2874Srgrimes if (t == tSLASH) { 2884Srgrimes t = db_read_token(); 2894Srgrimes if (t != tIDENT) { 2904Srgrimes db_printf("Bad modifier\n"); 2914Srgrimes db_flush_lex(); 2924Srgrimes return; 2934Srgrimes } 2944Srgrimes db_strcpy(modif, db_tok_string); 2954Srgrimes } 2964Srgrimes else { 2974Srgrimes db_unread_token(t); 2984Srgrimes modif[0] = '\0'; 2994Srgrimes } 3004Srgrimes 3014Srgrimes if (db_expression(&addr)) { 3024Srgrimes db_dot = (db_addr_t) addr; 3034Srgrimes db_last_addr = db_dot; 3044Srgrimes have_addr = TRUE; 3054Srgrimes } 3064Srgrimes else { 3074Srgrimes addr = (db_expr_t) db_dot; 3084Srgrimes have_addr = FALSE; 3094Srgrimes } 3104Srgrimes t = db_read_token(); 3114Srgrimes if (t == tCOMMA) { 3124Srgrimes if (!db_expression(&count)) { 3134Srgrimes db_printf("Count missing\n"); 3144Srgrimes db_flush_lex(); 3154Srgrimes return; 3164Srgrimes } 3174Srgrimes } 3184Srgrimes else { 3194Srgrimes db_unread_token(t); 3204Srgrimes count = -1; 3214Srgrimes } 3224Srgrimes if ((cmd->flag & CS_MORE) == 0) { 3234Srgrimes db_skip_to_eol(); 3244Srgrimes } 3254Srgrimes } 3264Srgrimes } 3274Srgrimes *last_cmdp = cmd; 3284Srgrimes if (cmd != 0) { 3294Srgrimes /* 3304Srgrimes * Execute the command. 3314Srgrimes */ 3324Srgrimes (*cmd->fcn)(addr, have_addr, count, modif); 3334Srgrimes 3344Srgrimes if (cmd->flag & CS_SET_DOT) { 3354Srgrimes /* 3364Srgrimes * If command changes dot, set dot to 3374Srgrimes * previous address displayed (if 'ed' style). 3384Srgrimes */ 3394Srgrimes if (db_ed_style) { 3404Srgrimes db_dot = db_prev; 3414Srgrimes } 3424Srgrimes else { 3434Srgrimes db_dot = db_next; 3444Srgrimes } 3454Srgrimes } 3464Srgrimes else { 3474Srgrimes /* 3484Srgrimes * If command does not change dot, 3494Srgrimes * set 'next' location to be the same. 3504Srgrimes */ 3514Srgrimes db_next = db_dot; 3524Srgrimes } 3534Srgrimes } 3544Srgrimes} 3554Srgrimes 3564Srgrimes/* 3574Srgrimes * 'show' commands 3584Srgrimes */ 3592112Swollman 36012515Sphkstatic struct command db_show_all_cmds[] = { 3614Srgrimes#if 0 3621147Sguido { "threads", db_show_all_threads, 0, 0 }, 3632320Sdg#endif 3641549Srgrimes { "procs", db_ps, 0, 0 }, 3654Srgrimes { (char *)0 } 3664Srgrimes}; 3674Srgrimes 36812515Sphkstatic struct command db_show_cmds[] = { 3694Srgrimes { "all", 0, 0, db_show_all_cmds }, 3704Srgrimes { "registers", db_show_regs, 0, 0 }, 3714Srgrimes { "breaks", db_listbreak_cmd, 0, 0 }, 3724Srgrimes#if 0 3734Srgrimes { "thread", db_show_one_thread, 0, 0 }, 3744Srgrimes#endif 3754Srgrimes#if 0 3764Srgrimes { "port", ipc_port_print, 0, 0 }, 3774Srgrimes#endif 3784Srgrimes { (char *)0, } 3794Srgrimes}; 3804Srgrimes 38112515Sphkstatic struct command db_command_table[] = { 3824Srgrimes { "print", db_print_cmd, 0, 0 }, 3836920Sjoerg { "p", db_print_cmd, 0, 0 }, 3844Srgrimes { "examine", db_examine_cmd, CS_SET_DOT, 0 }, 3854Srgrimes { "x", db_examine_cmd, CS_SET_DOT, 0 }, 3864Srgrimes { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, 3874Srgrimes { "set", db_set_cmd, CS_OWN, 0 }, 3884Srgrimes { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 3894Srgrimes { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 3904Srgrimes { "delete", db_delete_cmd, 0, 0 }, 3914Srgrimes { "d", db_delete_cmd, 0, 0 }, 3924Srgrimes { "break", db_breakpoint_cmd, 0, 0 }, 3934Srgrimes { "dwatch", db_deletewatch_cmd, 0, 0 }, 3944Srgrimes { "watch", db_watchpoint_cmd, CS_MORE,0 }, 3954Srgrimes { "step", db_single_step_cmd, 0, 0 }, 3964Srgrimes { "s", db_single_step_cmd, 0, 0 }, 3974Srgrimes { "continue", db_continue_cmd, 0, 0 }, 3984Srgrimes { "c", db_continue_cmd, 0, 0 }, 3994Srgrimes { "until", db_trace_until_call_cmd,0, 0 }, 4004Srgrimes { "next", db_trace_until_matching_cmd,0, 0 }, 4014Srgrimes { "match", db_trace_until_matching_cmd,0, 0 }, 4024Srgrimes { "trace", db_stack_trace_cmd, 0, 0 }, 4034Srgrimes { "call", db_fncall, CS_OWN, 0 }, 4044Srgrimes { "show", 0, 0, db_show_cmds }, 4051147Sguido { "ps", db_ps, 0, 0 }, 40617848Spst { "gdb", db_gdb, 0, 0 }, 4074Srgrimes { (char *)0, } 4084Srgrimes}; 4094Srgrimes 41012515Sphkstatic struct command *db_last_command = 0; 4114Srgrimes 4127090Sbde#if 0 4134Srgrimesvoid 4144Srgrimesdb_help_cmd() 4154Srgrimes{ 4164Srgrimes struct command *cmd = db_command_table; 4174Srgrimes 4184Srgrimes while (cmd->name != 0) { 4194Srgrimes db_printf("%-12s", cmd->name); 4204Srgrimes db_end_line(); 4214Srgrimes cmd++; 4224Srgrimes } 4234Srgrimes} 4247090Sbde#endif 4254Srgrimes 42633296Sbde/* 42733296Sbde * At least one non-optional command must be implemented using 42833296Sbde * DB_COMMAND() so that db_cmd_set gets created. Here is one. 42933296Sbde */ 43033296SbdeDB_COMMAND(panic, db_panic) 4316204Sphk{ 4327170Sdg panic("from debugger"); 4336204Sphk} 4346204Sphk 4356204Sphkvoid 4364Srgrimesdb_command_loop() 4374Srgrimes{ 4384Srgrimes /* 4394Srgrimes * Initialize 'prev' and 'next' to dot. 4404Srgrimes */ 4414Srgrimes db_prev = db_dot; 4424Srgrimes db_next = db_dot; 4434Srgrimes 4444Srgrimes db_cmd_loop_done = 0; 4454Srgrimes while (!db_cmd_loop_done) { 4464Srgrimes 4474Srgrimes (void) setjmp(db_jmpbuf); 4484Srgrimes if (db_print_position() != 0) 4494Srgrimes db_printf("\n"); 4504Srgrimes 4514Srgrimes db_printf("db> "); 4524Srgrimes (void) db_read_line(); 4534Srgrimes 45418296Sbde db_command(&db_last_command, db_command_table, 45518296Sbde (struct command **)&db_cmd_set.ls_items[0]); 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 */ 47412515Sphkstatic void 47510348Sbdedb_fncall(dummy1, dummy2, dummy3, dummy4) 47610348Sbde db_expr_t dummy1; 47710348Sbde boolean_t dummy2; 47810348Sbde db_expr_t dummy3; 47910348Sbde char * dummy4; 4804Srgrimes{ 4814Srgrimes db_expr_t fn_addr; 48212473Sbde#define MAXARGS 11 /* XXX only 10 are passed */ 4834Srgrimes db_expr_t args[MAXARGS]; 4844Srgrimes int nargs = 0; 4854Srgrimes db_expr_t retval; 48612473Sbde typedef db_expr_t fcn_10args_t __P((db_expr_t, db_expr_t, db_expr_t, 48712473Sbde db_expr_t, db_expr_t, db_expr_t, 48812473Sbde db_expr_t, db_expr_t, db_expr_t, 48912473Sbde db_expr_t)); 49012473Sbde fcn_10args_t *func; 4914Srgrimes int t; 4924Srgrimes 4934Srgrimes if (!db_expression(&fn_addr)) { 4944Srgrimes db_printf("Bad function\n"); 4954Srgrimes db_flush_lex(); 4964Srgrimes return; 4974Srgrimes } 49812473Sbde func = (fcn_10args_t *)fn_addr; /* XXX */ 4994Srgrimes 5004Srgrimes t = db_read_token(); 5014Srgrimes if (t == tLPAREN) { 5024Srgrimes if (db_expression(&args[0])) { 5034Srgrimes nargs++; 5044Srgrimes while ((t = db_read_token()) == tCOMMA) { 5054Srgrimes if (nargs == MAXARGS) { 5064Srgrimes db_printf("Too many arguments\n"); 5074Srgrimes db_flush_lex(); 5084Srgrimes return; 5094Srgrimes } 5104Srgrimes if (!db_expression(&args[nargs])) { 5114Srgrimes db_printf("Argument missing\n"); 5124Srgrimes db_flush_lex(); 5134Srgrimes return; 5144Srgrimes } 5154Srgrimes nargs++; 5164Srgrimes } 5174Srgrimes db_unread_token(t); 5184Srgrimes } 5194Srgrimes if (db_read_token() != tRPAREN) { 5204Srgrimes db_printf("?\n"); 5214Srgrimes db_flush_lex(); 5224Srgrimes return; 5234Srgrimes } 5244Srgrimes } 5254Srgrimes db_skip_to_eol(); 5264Srgrimes 5274Srgrimes while (nargs < MAXARGS) { 5284Srgrimes args[nargs++] = 0; 5294Srgrimes } 5304Srgrimes 5314Srgrimes retval = (*func)(args[0], args[1], args[2], args[3], args[4], 5324Srgrimes args[5], args[6], args[7], args[8], args[9] ); 53337506Sbde db_printf("%#r\n", retval); 5344Srgrimes} 53517848Spst 53617848Spst/* Enter GDB remote protocol debugger on the next trap. */ 53717848Spst 53817848Spststatic void 53917848Spstdb_gdb (dummy1, dummy2, dummy3, dummy4) 54017848Spst db_expr_t dummy1; 54117848Spst boolean_t dummy2; 54217848Spst db_expr_t dummy3; 54317848Spst char * dummy4; 54417848Spst{ 54517848Spst boothowto ^= RB_GDB; 54617848Spst 54717848Spst db_printf("Next trap will enter %s\n", 54817848Spst boothowto & RB_GDB ? "GDB remote protocol mode" 54917848Spst : "DDB debugger"); 55017848Spst} 551