db_command.c revision 163909
150477Speter/*- 21817Sdg * Mach Operating System 31817Sdg * Copyright (c) 1991,1990 Carnegie Mellon University 41541Srgrimes * All Rights Reserved. 51541Srgrimes * 61541Srgrimes * Permission to use, copy, modify and distribute this software and its 7160798Sjhb * documentation is hereby granted, provided that both the copyright 81541Srgrimes * notice and this permission notice appear in all copies of the 9146806Srwatson * software, derivative works or modified versions, and any portions 10146806Srwatson * thereof, and that both notices appear in supporting documentation. 11146806Srwatson * 12146806Srwatson * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 13146806Srwatson * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14160798Sjhb * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15160798Sjhb * 1611294Sswallace * Carnegie Mellon requests users of this software to return to 1710905Sbde * 181541Srgrimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 1910905Sbde * School of Computer Science 2010905Sbde * Carnegie Mellon University 211541Srgrimes * Pittsburgh PA 15213-3890 221541Srgrimes * 231541Srgrimes * any improvements or extensions that they make and grant Carnegie the 241541Srgrimes * rights to redistribute these changes. 251541Srgrimes */ 2699855Salfred/* 271541Srgrimes * Author: David B. Golub, Carnegie Mellon University 281541Srgrimes * Date: 7/90 291541Srgrimes */ 3069449Salfred/* 31160797Sjhb * Command dispatcher. 32160797Sjhb */ 33104747Srwatson 34104747Srwatson#include <sys/cdefs.h> 35123408Speter__FBSDID("$FreeBSD: head/sys/ddb/db_command.c 163909 2006-11-02 11:47:38Z kib $"); 36123408Speter 371541Srgrimes#include <sys/param.h> 381541Srgrimes#include <sys/linker_set.h> 3911294Sswallace#include <sys/lock.h> 4011294Sswallace#include <sys/kdb.h> 4111294Sswallace#include <sys/mutex.h> 4211294Sswallace#include <sys/proc.h> 431541Srgrimes#include <sys/reboot.h> 441541Srgrimes#include <sys/signalvar.h> 451541Srgrimes#include <sys/systm.h> 461541Srgrimes#include <sys/cons.h> 471541Srgrimes#include <sys/watchdog.h> 481541Srgrimes 49160798Sjhb#include <ddb/ddb.h> 50160798Sjhb#include <ddb/db_command.h> 51146806Srwatson#include <ddb/db_lex.h> 52160798Sjhb#include <ddb/db_output.h> 53160798Sjhb 54146806Srwatson#include <machine/cpu.h> 55160798Sjhb#include <machine/setjmp.h> 56146806Srwatson 57160798Sjhb/* 5812216Sbde * Exported global variables 5912216Sbde */ 6012216Sbdeboolean_t db_cmd_loop_done; 61160798Sjhbdb_addr_t db_dot; 62160798Sjhbdb_addr_t db_last_addr; 63146806Srwatsondb_addr_t db_prev; 64146806Srwatsondb_addr_t db_next; 65160798Sjhb 66160798SjhbSET_DECLARE(db_cmd_set, struct command); 67160798SjhbSET_DECLARE(db_show_cmd_set, struct command); 68146806Srwatson 69160798Sjhbstatic db_cmdfcn_t db_fncall; 70160798Sjhbstatic db_cmdfcn_t db_gdb; 71160798Sjhbstatic db_cmdfcn_t db_halt; 72160798Sjhbstatic db_cmdfcn_t db_kill; 73160798Sjhbstatic db_cmdfcn_t db_reset; 74160798Sjhbstatic db_cmdfcn_t db_stack_trace; 75146806Srwatsonstatic db_cmdfcn_t db_stack_trace_all; 76160798Sjhbstatic db_cmdfcn_t db_watchdog; 77146806Srwatson 78160798Sjhb/* 79146806Srwatson * 'show' commands 80160798Sjhb */ 81160798Sjhb 82146806Srwatsonstatic struct command db_show_all_cmds[] = { 8312216Sbde { "procs", db_ps, 0, 0 }, 84160798Sjhb { (char *)0 } 85160798Sjhb}; 86160798Sjhb 87160798Sjhbstatic struct command_table db_show_all_table = { 88160798Sjhb db_show_all_cmds 89146806Srwatson}; 90160798Sjhb 91146806Srwatsonstatic struct command db_show_cmds[] = { 92160798Sjhb { "all", 0, 0, &db_show_all_table }, 93146806Srwatson { "registers", db_show_regs, 0, 0 }, 94160798Sjhb { "breaks", db_listbreak_cmd, 0, 0 }, 95146806Srwatson { "threads", db_show_threads, 0, 0 }, 96146806Srwatson { (char *)0, } 97146806Srwatson}; 98160798Sjhb 99146806Srwatsonstatic struct command_table db_show_table = { 100146806Srwatson db_show_cmds, 101160798Sjhb SET_BEGIN(db_show_cmd_set), 102146806Srwatson SET_LIMIT(db_show_cmd_set) 103146806Srwatson}; 104160798Sjhb 105146806Srwatsonstatic struct command db_commands[] = { 106146806Srwatson { "print", db_print_cmd, 0, 0 }, 107160798Sjhb { "p", db_print_cmd, 0, 0 }, 108160798Sjhb { "examine", db_examine_cmd, CS_SET_DOT, 0 }, 109160798Sjhb { "x", db_examine_cmd, CS_SET_DOT, 0 }, 110160798Sjhb { "search", db_search_cmd, CS_OWN|CS_SET_DOT, 0 }, 111160798Sjhb { "set", db_set_cmd, CS_OWN, 0 }, 112160798Sjhb { "write", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 113160798Sjhb { "w", db_write_cmd, CS_MORE|CS_SET_DOT, 0 }, 114160798Sjhb { "delete", db_delete_cmd, 0, 0 }, 115160798Sjhb { "d", db_delete_cmd, 0, 0 }, 116160798Sjhb { "break", db_breakpoint_cmd, 0, 0 }, 117160798Sjhb { "b", db_breakpoint_cmd, 0, 0 }, 118160798Sjhb { "dwatch", db_deletewatch_cmd, 0, 0 }, 119146806Srwatson { "watch", db_watchpoint_cmd, CS_MORE,0 }, 120160798Sjhb { "dhwatch", db_deletehwatch_cmd, 0, 0 }, 121146806Srwatson { "hwatch", db_hwatchpoint_cmd, 0, 0 }, 122160798Sjhb { "step", db_single_step_cmd, 0, 0 }, 123146806Srwatson { "s", db_single_step_cmd, 0, 0 }, 124146806Srwatson { "continue", db_continue_cmd, 0, 0 }, 125160798Sjhb { "c", db_continue_cmd, 0, 0 }, 126160798Sjhb { "until", db_trace_until_call_cmd,0, 0 }, 12721776Sbde { "next", db_trace_until_matching_cmd,0, 0 }, 12821776Sbde { "match", db_trace_until_matching_cmd,0, 0 }, 12921776Sbde { "trace", db_stack_trace, CS_OWN, 0 }, 130160798Sjhb { "t", db_stack_trace, CS_OWN, 0 }, 131146806Srwatson { "alltrace", db_stack_trace_all, 0, 0 }, 132160798Sjhb { "where", db_stack_trace, CS_OWN, 0 }, 133160798Sjhb { "bt", db_stack_trace, CS_OWN, 0 }, 134160798Sjhb { "call", db_fncall, CS_OWN, 0 }, 135160798Sjhb { "show", 0, 0, &db_show_table }, 136146806Srwatson { "ps", db_ps, 0, 0 }, 137160798Sjhb { "gdb", db_gdb, 0, 0 }, 138146806Srwatson { "halt", db_halt, 0, 0 }, 139160798Sjhb { "reboot", db_reset, 0, 0 }, 140160798Sjhb { "reset", db_reset, 0, 0 }, 141160798Sjhb { "kill", db_kill, CS_OWN, 0 }, 142160798Sjhb { "watchdog", db_watchdog, 0, 0 }, 143146806Srwatson { "thread", db_set_thread, CS_OWN, 0 }, 144160798Sjhb { (char *)0, } 145146806Srwatson}; 146160798Sjhb 147146806Srwatsonstatic struct command_table db_command_table = { 148160798Sjhb db_commands, 149160798Sjhb SET_BEGIN(db_cmd_set), 150160798Sjhb SET_LIMIT(db_cmd_set) 151146806Srwatson}; 152146806Srwatson 153160798Sjhbstatic struct command *db_last_command = 0; 154146806Srwatson 155160798Sjhb/* 156146806Srwatson * if 'ed' style: 'dot' is set at start of last item printed, 157160798Sjhb * and '+' points to next line. 158146806Srwatson * Otherwise: 'dot' points to next item, '..' points to last. 159146806Srwatson */ 160160798Sjhbstatic boolean_t db_ed_style = TRUE; 161160798Sjhb 162160798Sjhb/* 163146806Srwatson * Utility routine - discard tokens through end-of-line. 164160798Sjhb */ 165146806Srwatsonvoid 166160798Sjhbdb_skip_to_eol() 167160798Sjhb{ 168146806Srwatson int t; 169160798Sjhb do { 170146806Srwatson t = db_read_token(); 171146806Srwatson } while (t != tEOL); 172146806Srwatson} 173160798Sjhb 174146806Srwatson/* 175160798Sjhb * Results of command search. 176146806Srwatson */ 177160798Sjhb#define CMD_UNIQUE 0 178146806Srwatson#define CMD_FOUND 1 179160798Sjhb#define CMD_NONE 2 180160798Sjhb#define CMD_AMBIGUOUS 3 181160798Sjhb#define CMD_HELP 4 182146806Srwatson 183160798Sjhbstatic void db_cmd_match(char *name, struct command *cmd, 184160798Sjhb struct command **cmdp, int *resultp); 185160798Sjhbstatic void db_cmd_list(struct command_table *table); 186146806Srwatsonstatic int db_cmd_search(char *name, struct command_table *table, 187160798Sjhb struct command **cmdp); 188146806Srwatsonstatic void db_command(struct command **last_cmdp, 189146806Srwatson struct command_table *cmd_table); 190160798Sjhb 191146806Srwatson/* 192146806Srwatson * Helper function to match a single command. 193160798Sjhb */ 194160798Sjhbstatic void 195146806Srwatsondb_cmd_match(name, cmd, cmdp, resultp) 196160798Sjhb char * name; 197123750Speter struct command *cmd; 19812216Sbde struct command **cmdp; /* out */ 199160798Sjhb int * resultp; 200146806Srwatson{ 201146806Srwatson char *lp, *rp; 202160798Sjhb int c; 203160798Sjhb 204146806Srwatson lp = name; 205160798Sjhb rp = cmd->name; 206146806Srwatson while ((c = *lp) == *rp) { 207160798Sjhb if (c == 0) { 208146806Srwatson /* complete match */ 209160798Sjhb *cmdp = cmd; 210146806Srwatson *resultp = CMD_UNIQUE; 211160798Sjhb return; 212160798Sjhb } 213146806Srwatson lp++; 214160798Sjhb rp++; 215146806Srwatson } 216160798Sjhb if (c == 0) { 217146806Srwatson /* end of name, not end of command - 218160798Sjhb partial match */ 219146806Srwatson if (*resultp == CMD_FOUND) { 220160798Sjhb *resultp = CMD_AMBIGUOUS; 221146806Srwatson /* but keep looking for a full match - 222160798Sjhb this lets us match single letters */ 223146806Srwatson } else { 224160798Sjhb *cmdp = cmd; 225146806Srwatson *resultp = CMD_FOUND; 226160798Sjhb } 227160798Sjhb } 228160798Sjhb} 22921776Sbde 23021776Sbde/* 231160798Sjhb * Search for command prefix. 232146806Srwatson */ 233160798Sjhbstatic int 234146806Srwatsondb_cmd_search(name, table, cmdp) 235160798Sjhb char * name; 236146806Srwatson struct command_table *table; 237146806Srwatson struct command **cmdp; /* out */ 238160798Sjhb{ 239146806Srwatson struct command *cmd; 240160798Sjhb struct command **aux_cmdp; 241146806Srwatson int result = CMD_NONE; 242160798Sjhb 243146806Srwatson for (cmd = table->table; cmd->name != 0; cmd++) { 244146806Srwatson db_cmd_match(name, cmd, cmdp, &result); 245160798Sjhb if (result == CMD_UNIQUE) 246146806Srwatson return (CMD_UNIQUE); 247160798Sjhb } 248146806Srwatson if (table->aux_tablep != NULL) 249160798Sjhb for (aux_cmdp = table->aux_tablep; 250146806Srwatson aux_cmdp < table->aux_tablep_end; 251160798Sjhb aux_cmdp++) { 252160798Sjhb db_cmd_match(name, *aux_cmdp, cmdp, &result); 253160798Sjhb if (result == CMD_UNIQUE) 254146806Srwatson return (CMD_UNIQUE); 255146806Srwatson } 256146806Srwatson if (result == CMD_NONE) { 257160798Sjhb /* check for 'help' */ 258160798Sjhb if (name[0] == 'h' && name[1] == 'e' 259160798Sjhb && name[2] == 'l' && name[3] == 'p') 260160798Sjhb result = CMD_HELP; 261160798Sjhb } 262160798Sjhb return (result); 263160798Sjhb} 264160798Sjhb 265146806Srwatsonstatic void 266160798Sjhbdb_cmd_list(table) 267160798Sjhb struct command_table *table; 268146806Srwatson{ 269160798Sjhb register struct command *cmd; 270160798Sjhb register struct command **aux_cmdp; 271160798Sjhb 272146806Srwatson for (cmd = table->table; cmd->name != 0; cmd++) { 273146806Srwatson db_printf("%-12s", cmd->name); 274160798Sjhb db_end_line(12); 275146806Srwatson } 276160798Sjhb if (table->aux_tablep == NULL) 277146806Srwatson return; 278160798Sjhb for (aux_cmdp = table->aux_tablep; aux_cmdp < table->aux_tablep_end; 279160798Sjhb aux_cmdp++) { 280160798Sjhb db_printf("%-12s", (*aux_cmdp)->name); 281146806Srwatson db_end_line(12); 282160798Sjhb } 283146806Srwatson} 284160798Sjhb 285160798Sjhbstatic void 286160798Sjhbdb_command(last_cmdp, cmd_table) 287146806Srwatson struct command **last_cmdp; /* IN_OUT */ 288160798Sjhb struct command_table *cmd_table; 289160798Sjhb{ 290146806Srwatson struct command *cmd; 291146806Srwatson int t; 2921541Srgrimes char modif[TOK_STRING_SIZE]; 2931541Srgrimes db_expr_t addr, count; 2941541Srgrimes boolean_t have_addr = FALSE; 2951541Srgrimes int result; 2961541Srgrimes 297146806Srwatson t = db_read_token(); 298146806Srwatson if (t == tEOL) { 299146806Srwatson /* empty line repeats last command, at 'next' */ 300146806Srwatson cmd = *last_cmdp; 30130740Sphk addr = (db_expr_t)db_next; 302161325Sjhb have_addr = FALSE; 303160798Sjhb count = 1; 304146806Srwatson modif[0] = '\0'; 305160798Sjhb } 306146806Srwatson else if (t == tEXCL) { 307160798Sjhb db_fncall((db_expr_t)0, (boolean_t)0, (db_expr_t)0, (char *)0); 308146806Srwatson return; 309146806Srwatson } 310160798Sjhb else if (t != tIDENT) { 311146806Srwatson db_printf("?\n"); 312160798Sjhb db_flush_lex(); 313146806Srwatson return; 314160798Sjhb } 315146806Srwatson else { 316160798Sjhb /* 317146806Srwatson * Search for command 318160798Sjhb */ 319160798Sjhb while (cmd_table) { 320160798Sjhb result = db_cmd_search(db_tok_string, 321146806Srwatson cmd_table, 322146806Srwatson &cmd); 323146806Srwatson switch (result) { 32469449Salfred case CMD_NONE: 325160798Sjhb db_printf("No such command\n"); 326146806Srwatson db_flush_lex(); 32769449Salfred return; 328123750Speter case CMD_AMBIGUOUS: 329160798Sjhb db_printf("Ambiguous\n"); 330146806Srwatson db_flush_lex(); 33169449Salfred return; 332123750Speter case CMD_HELP: 333160798Sjhb db_cmd_list(cmd_table); 334146806Srwatson db_flush_lex(); 335123750Speter return; 336146806Srwatson default: 337160798Sjhb break; 338146806Srwatson } 339160798Sjhb if ((cmd_table = cmd->more) != NULL) { 340146806Srwatson t = db_read_token(); 341146806Srwatson if (t != tIDENT) { 342160798Sjhb db_cmd_list(cmd_table); 343146806Srwatson db_flush_lex(); 344146806Srwatson return; 345146806Srwatson } 346146806Srwatson } 3471541Srgrimes } 34849428Sjkh 349160798Sjhb if ((cmd->flag & CS_OWN) == 0) { 350160798Sjhb /* 351160798Sjhb * Standard syntax: 352146806Srwatson * command [/modifier] [addr] [,count] 353146806Srwatson */ 354146806Srwatson t = db_read_token(); 355146806Srwatson if (t == tSLASH) { 356160798Sjhb t = db_read_token(); 357160798Sjhb if (t != tIDENT) { 358160798Sjhb db_printf("Bad modifier\n"); 359160798Sjhb db_flush_lex(); 360160798Sjhb return; 361146806Srwatson } 362160798Sjhb db_strcpy(modif, db_tok_string); 363146806Srwatson } 364146806Srwatson else { 365160798Sjhb db_unread_token(t); 366146806Srwatson modif[0] = '\0'; 367146806Srwatson } 368160798Sjhb 369146806Srwatson if (db_expression(&addr)) { 370160798Sjhb db_dot = (db_addr_t) addr; 371146806Srwatson db_last_addr = db_dot; 372146806Srwatson have_addr = TRUE; 373160798Sjhb } 374146806Srwatson else { 375160798Sjhb addr = (db_expr_t) db_dot; 376146806Srwatson have_addr = FALSE; 377160798Sjhb } 378146806Srwatson t = db_read_token(); 379160798Sjhb if (t == tCOMMA) { 380146806Srwatson if (!db_expression(&count)) { 381160798Sjhb db_printf("Count missing\n"); 382146806Srwatson db_flush_lex(); 383146806Srwatson return; 384160798Sjhb } 385160798Sjhb } 386160798Sjhb else { 387160798Sjhb db_unread_token(t); 388160798Sjhb count = -1; 389146806Srwatson } 390160798Sjhb if ((cmd->flag & CS_MORE) == 0) { 391146806Srwatson db_skip_to_eol(); 3922124Sdg } 3932124Sdg } 3942124Sdg } 3952124Sdg *last_cmdp = cmd; 396146806Srwatson if (cmd != 0) { 397146806Srwatson /* 398146806Srwatson * Execute the command. 399146806Srwatson */ 400146806Srwatson db_enable_pager(); 401146806Srwatson (*cmd->fcn)(addr, have_addr, count, modif); 402146806Srwatson db_disable_pager(); 403146806Srwatson 404146806Srwatson if (cmd->flag & CS_SET_DOT) { 405146806Srwatson /* 40612864Speter * If command changes dot, set dot to 40712864Speter * previous address displayed (if 'ed' style). 40814215Speter */ 409160798Sjhb if (db_ed_style) { 410146806Srwatson db_dot = db_prev; 411160798Sjhb } 412146806Srwatson else { 413160798Sjhb db_dot = db_next; 414146806Srwatson } 415146806Srwatson } 416160798Sjhb else { 417146806Srwatson /* 418160798Sjhb * If command does not change dot, 419160798Sjhb * set 'next' location to be the same. 420146806Srwatson */ 421160798Sjhb db_next = db_dot; 422146806Srwatson } 423160798Sjhb } 424146806Srwatson} 425160798Sjhb 426146806Srwatson/* 427160798Sjhb * At least one non-optional command must be implemented using 428160798Sjhb * DB_COMMAND() so that db_cmd_set gets created. Here is one. 429146806Srwatson */ 43014219SpeterDB_COMMAND(panic, db_panic) 431160798Sjhb{ 432146806Srwatson db_disable_pager(); 433160798Sjhb panic("from debugger"); 434146806Srwatson} 435160798Sjhb 436146806Srwatsonvoid 437160798Sjhbdb_command_loop() 438156134Sdavidxu{ 439160798Sjhb /* 440160798Sjhb * Initialize 'prev' and 'next' to dot. 441151576Sdavidxu */ 442151576Sdavidxu db_prev = db_dot; 443160798Sjhb db_next = db_dot; 444151576Sdavidxu 445160798Sjhb db_cmd_loop_done = 0; 446160798Sjhb while (!db_cmd_loop_done) { 447146806Srwatson if (db_print_position() != 0) 448146806Srwatson db_printf("\n"); 449146806Srwatson 450146806Srwatson db_printf("db> "); 451146806Srwatson (void) db_read_line(); 452146806Srwatson 453146806Srwatson db_command(&db_last_command, &db_command_table); 454146806Srwatson } 455160798Sjhb} 456146806Srwatson 45714219Spetervoid 458160798Sjhbdb_error(s) 459146806Srwatson const char *s; 460160798Sjhb{ 461160798Sjhb if (s) 462146806Srwatson db_printf("%s", s); 463160798Sjhb db_flush_lex(); 464160798Sjhb kdb_reenter(); 465160798Sjhb} 466160798Sjhb 467160798Sjhb 468151867Sdavidxu/* 469151867Sdavidxu * Call random function: 470152845Sdavidxu * !expr(arg,arg,arg) 471152845Sdavidxu */ 472152845Sdavidxu 473152845Sdavidxu/* The generic implementation supports a maximum of 10 arguments. */ 474152845Sdavidxutypedef db_expr_t __db_f(db_expr_t, db_expr_t, db_expr_t, db_expr_t, 475152845Sdavidxu db_expr_t, db_expr_t, db_expr_t, db_expr_t, db_expr_t, db_expr_t); 476146806Srwatson 477146806Srwatsonstatic __inline int 478146806Srwatsondb_fncall_generic(db_expr_t addr, db_expr_t *rv, int nargs, db_expr_t args[]) 479146806Srwatson{ 480146806Srwatson __db_f *f = (__db_f *)addr; 481146806Srwatson 482146806Srwatson if (nargs > 10) { 483146806Srwatson db_printf("Too many arguments (max 10)\n"); 484160798Sjhb return (0); 485146806Srwatson } 486146806Srwatson *rv = (*f)(args[0], args[1], args[2], args[3], args[4], args[5], 487160798Sjhb args[6], args[7], args[8], args[9]); 488160798Sjhb return (1); 489146806Srwatson} 490146806Srwatson 491160798Sjhbstatic void 492146806Srwatsondb_fncall(dummy1, dummy2, dummy3, dummy4) 493160798Sjhb db_expr_t dummy1; 494146806Srwatson boolean_t dummy2; 495160798Sjhb db_expr_t dummy3; 496160798Sjhb char * dummy4; 497160798Sjhb{ 498146806Srwatson db_expr_t fn_addr; 499146806Srwatson db_expr_t args[DB_MAXARGS]; 500146806Srwatson int nargs = 0; 501146806Srwatson db_expr_t retval; 502146806Srwatson int t; 503146806Srwatson 504146806Srwatson if (!db_expression(&fn_addr)) { 505146806Srwatson db_printf("Bad function\n"); 506147813Sjhb db_flush_lex(); 507160798Sjhb return; 508147813Sjhb } 509160798Sjhb 510147813Sjhb t = db_read_token(); 511146806Srwatson if (t == tLPAREN) { 512146806Srwatson if (db_expression(&args[0])) { 513146806Srwatson nargs++; 514146806Srwatson while ((t = db_read_token()) == tCOMMA) { 515146806Srwatson if (nargs == DB_MAXARGS) { 516146806Srwatson db_printf("Too many arguments (max %d)\n", DB_MAXARGS); 51751138Salfred db_flush_lex(); 518160798Sjhb return; 519146806Srwatson } 520146806Srwatson if (!db_expression(&args[nargs])) { 521160798Sjhb db_printf("Argument missing\n"); 522146806Srwatson db_flush_lex(); 523160798Sjhb return; 524146806Srwatson } 52525537Sdfr nargs++; 526160798Sjhb } 527160798Sjhb db_unread_token(t); 528146806Srwatson } 529160798Sjhb if (db_read_token() != tRPAREN) { 530160798Sjhb db_printf("?\n"); 531160798Sjhb db_flush_lex(); 532160798Sjhb return; 533160798Sjhb } 534160798Sjhb } 535160798Sjhb db_skip_to_eol(); 536146806Srwatson db_disable_pager(); 537160798Sjhb 538160798Sjhb if (DB_CALL(fn_addr, &retval, nargs, args)) 539160798Sjhb db_printf("= %#lr\n", (long)retval); 540146806Srwatson} 541160798Sjhb 542146806Srwatsonstatic void 543146806Srwatsondb_halt(db_expr_t dummy, boolean_t dummy2, db_expr_t dummy3, char *dummy4) 544160798Sjhb{ 545160798Sjhb 546146806Srwatson cpu_halt(); 547146806Srwatson} 548160798Sjhb 549146806Srwatsonstatic void 550160798Sjhbdb_kill(dummy1, dummy2, dummy3, dummy4) 551160798Sjhb db_expr_t dummy1; 552160798Sjhb boolean_t dummy2; 553160798Sjhb db_expr_t dummy3; 554151867Sdavidxu char * dummy4; 555151867Sdavidxu{ 556160798Sjhb db_expr_t old_radix, pid, sig; 557146806Srwatson struct proc *p; 558146806Srwatson 559160798Sjhb#define DB_ERROR(f) do { db_printf f; db_flush_lex(); goto out; } while (0) 560160798Sjhb 561160798Sjhb /* 56234925Sdufault * PIDs and signal numbers are typically represented in base 563160798Sjhb * 10, so make that the default here. It can, of course, be 564146806Srwatson * overridden by specifying a prefix. 565160798Sjhb */ 566146806Srwatson old_radix = db_radix; 56734925Sdufault db_radix = 10; 568160798Sjhb /* Retrieve arguments. */ 569146806Srwatson if (!db_expression(&sig)) 570146806Srwatson DB_ERROR(("Missing signal number\n")); 571160798Sjhb if (!db_expression(&pid)) 57234925Sdufault DB_ERROR(("Missing process ID\n")); 573160798Sjhb db_skip_to_eol(); 574160798Sjhb if (sig < 0 || sig > _SIG_MAXSIG) 575160798Sjhb DB_ERROR(("Signal number out of range\n")); 576160798Sjhb 577146806Srwatson /* 578160798Sjhb * Find the process in question. allproc_lock is not needed 579160798Sjhb * since we're in DDB. 580146806Srwatson */ 581146806Srwatson /* sx_slock(&allproc_lock); */ 582146806Srwatson LIST_FOREACH(p, &allproc, p_list) 583160798Sjhb if (p->p_pid == pid) 584146806Srwatson break; 585160798Sjhb /* sx_sunlock(&allproc_lock); */ 586146806Srwatson if (p == NULL) 587160798Sjhb DB_ERROR(("Can't find process with pid %ld\n", (long) pid)); 588146806Srwatson 589160798Sjhb /* If it's already locked, bail; otherwise, do the deed. */ 590160798Sjhb if (PROC_TRYLOCK(p) == 0) 591146806Srwatson DB_ERROR(("Can't lock process with pid %ld\n", (long) pid)); 592146806Srwatson else { 593160798Sjhb psignal(p, sig); 594160798Sjhb PROC_UNLOCK(p); 595146806Srwatson } 596160798Sjhb 597146806Srwatsonout: 598146806Srwatson db_radix = old_radix; 599160798Sjhb#undef DB_ERROR 600146806Srwatson} 601160798Sjhb 602146806Srwatsonstatic void 603160798Sjhbdb_reset(dummy1, dummy2, dummy3, dummy4) 604146806Srwatson db_expr_t dummy1; 605160798Sjhb boolean_t dummy2; 606146806Srwatson db_expr_t dummy3; 607160798Sjhb char * dummy4; 608146806Srwatson{ 609160798Sjhb 610146806Srwatson cpu_reset(); 611160798Sjhb} 612146806Srwatson 613160798Sjhbstatic void 614146806Srwatsondb_watchdog(dummy1, dummy2, dummy3, dummy4) 615160798Sjhb db_expr_t dummy1; 616146806Srwatson boolean_t dummy2; 617160798Sjhb db_expr_t dummy3; 618146806Srwatson char * dummy4; 619146806Srwatson{ 620160798Sjhb int i; 621160111Swsalamon 622160111Swsalamon /* 623160111Swsalamon * XXX: It might make sense to be able to set the watchdog to a 624160798Sjhb * XXX: timeout here so that failure or hang as a result of subsequent 625160111Swsalamon * XXX: ddb commands could be recovered by a reset. 626160111Swsalamon */ 627160111Swsalamon 628160798Sjhb EVENTHANDLER_INVOKE(watchdog_list, 0, &i); 629146806Srwatson} 630146806Srwatson 631160798Sjhbstatic void 632146806Srwatsondb_gdb(db_expr_t dummy1, boolean_t dummy2, db_expr_t dummy3, char *dummy4) 633146806Srwatson{ 634160798Sjhb 635146806Srwatson if (kdb_dbbe_select("gdb") != 0) 636160798Sjhb db_printf("The remote GDB backend could not be selected.\n"); 637146806Srwatson else 638160798Sjhb db_printf("Step to enter the remote GDB backend.\n"); 639160798Sjhb} 640146806Srwatson 641146806Srwatsonstatic void 642146806Srwatsondb_stack_trace(db_expr_t tid, boolean_t hastid, db_expr_t count, char *modif) 643146806Srwatson{ 644146806Srwatson struct thread *td; 645146806Srwatson db_expr_t radix; 646146806Srwatson pid_t pid; 647146806Srwatson int t; 648146806Srwatson 649146806Srwatson /* 650160798Sjhb * We parse our own arguments. We don't like the default radix. 651146806Srwatson */ 652146806Srwatson radix = db_radix; 653160798Sjhb db_radix = 10; 654146806Srwatson hastid = db_expression(&tid); 655146806Srwatson t = db_read_token(); 656160798Sjhb if (t == tCOMMA) { 657146806Srwatson if (!db_expression(&count)) { 658146806Srwatson db_printf("Count missing\n"); 659160798Sjhb db_flush_lex(); 660146806Srwatson return; 661160798Sjhb } 662146806Srwatson } else { 663160798Sjhb db_unread_token(t); 664146806Srwatson count = -1; 665160798Sjhb } 666160798Sjhb db_skip_to_eol(); 667160798Sjhb db_radix = radix; 668146806Srwatson 669160798Sjhb if (hastid) { 670146806Srwatson td = kdb_thr_lookup((lwpid_t)tid); 671146806Srwatson if (td == NULL) 672160798Sjhb td = kdb_thr_from_pid((pid_t)tid); 673160798Sjhb if (td == NULL) { 674160798Sjhb db_printf("Thread %d not found\n", (int)tid); 675160798Sjhb return; 676146806Srwatson } 677160798Sjhb } else 678146806Srwatson td = kdb_thread; 679160798Sjhb if (td->td_proc != NULL) 680146806Srwatson pid = td->td_proc->p_pid; 681160798Sjhb else 682146806Srwatson pid = -1; 683160798Sjhb db_printf("Tracing pid %d tid %ld td %p\n", pid, (long)td->td_tid, td); 684146806Srwatson db_trace_thread(td, count); 685160798Sjhb} 686160798Sjhb 687146806Srwatsonstatic void 688160798Sjhbdb_stack_trace_all(db_expr_t dummy, boolean_t dummy2, db_expr_t dummy3, 689146806Srwatson char *dummy4) 690146806Srwatson{ 691160798Sjhb struct proc *p; 692146806Srwatson struct thread *td; 693160798Sjhb jmp_buf jb; 694146806Srwatson void *prev_jb; 695160798Sjhb 696146806Srwatson LIST_FOREACH(p, &allproc, p_list) { 697160798Sjhb prev_jb = kdb_jmpbuf(jb); 698160798Sjhb if (setjmp(jb) == 0) { 699146806Srwatson FOREACH_THREAD_IN_PROC(p, td) { 700146806Srwatson db_printf("\nTracing command %s pid %d tid %ld td %p\n", 701160798Sjhb p->p_comm, p->p_pid, (long)td->td_tid, td); 702160798Sjhb db_trace_thread(td, -1); 703160798Sjhb if (db_pager_quit) { 704160798Sjhb kdb_jmpbuf(prev_jb); 705160798Sjhb return; 706146806Srwatson } 707160798Sjhb } 708146806Srwatson } 709146806Srwatson kdb_jmpbuf(prev_jb); 710160798Sjhb } 711160798Sjhb} 712160798Sjhb